anvilsign in

collin/anvil · 84b3fd31

docs: check off the TODO list; refresh session notes

Collin Richards · 2026-06-10 09:17 UTC · 84b3fd313100976e39f487119aa74182315ba92d · parent c4d49193 · browse files

modifiedTODO.md+84 −23
⋯ 5 unchanged lines
66 and tree pages, "browse files" link on the commit page, percent-encoded
77 ref names so branches with `/` work, and an unborn-HEAD fallback so a
88 repo whose HEAD names a missing branch no longer renders as empty.
9-- [ ] implement the CI artifact system _(designed — see `docs/ci-artifacts.md`;
10- implementation order is at the bottom of that doc)_
9+- [x] implement the CI artifact system _(done per `docs/ci-artifacts.md`:
10+ `artifacts:` in ci.yml with in-container meta extractors, broker
11+ collection via `download_from_container`, run-page list, downloads +
12+ `/{owner}/{repo}/artifacts/{rev}/{name}` alias + `browse: true` static
13+ sites, quota GC with branch-tip pinning, and a schema shim so the table
14+ appears on existing DBs. Verified end-to-end against real Docker incl.
15+ the GC path. Repo-deletion cleanup deferred: repo deletion doesn't exist.)_
1116 - every push triggers CI on the tip commit (already true); a run should be
1217 able to produce artifacts
1318 - artifacts are stored per-commit and served from anvil (download from the
⋯ 7 unchanged lines
2126 - use rustdoc as an example when testing the feature: it generates a big
2227 HTML subtree, so support rendering/serving a whole HTML artifact subtree
2328 the way the pages feature does (rustdoc output as a served site)
24-- [ ] repo mirroring to/from GitHub
25- - push mirror: pushes to an anvil repo get forwarded to a configured
26- GitHub remote
27- - pull mirror (maybe): a repo that virtually mirrors a GitHub repo and
28- just displays it here — periodically fetched, read-only on the anvil
29- side
30-- [ ] per-repository issue tracker
29+- [x] repo mirroring to GitHub (push mirror) _(per-repo "Mirror push URL" in
30+ settings (`repositories.mirror_url`, column shim for existing DBs);
31+ after every successful push over HTTP or SSH a background
32+ `git push --mirror` fires — shells out to git (gix can't push yet;
33+ runtime image now installs git). Credentials ride in the URL
34+ (`https://x-access-token:<token>@github.com/...`), stored as-is and
35+ redacted from logs. Verified e2e against a local bare "github".)_
36+ - pull mirror (maybe, NOT done): a repo that virtually mirrors a GitHub
37+ repo and just displays it here — periodically fetched, read-only on
38+ the anvil side
39+- [x] per-repository issue tracker _(`Issue`/`IssueComment` models with
40+ schema shims; per-repo numbering (#1, #2, …); list page with
41+ open/closed tabs, new-issue form, detail page with markdown bodies and
42+ comments, close/reopen (issue author or repo writer). Any logged-in
43+ reader can open issues and comment; visibility follows the repo.
44+ "Issues" link in the repo nav. CSRF on all forms. Verified e2e through
45+ the login + form flow. No labels/assignees/editing yet — deliberately
46+ minimal.)_
47+- [x] render a root `README.md` below the file tree on the repo page _(any
48+ case of `readme.md` at the root; reuses `render_markdown`, links to the
49+ blob view from the box header)_
50+- [x] push-to-create: `git push` to a repo that doesn't exist yet creates it
51+ _(it did NOT already work — both transports 404'd. Policy in
52+ `repos::create_on_push`: pusher must own the namespace or be admin;
53+ created repos are private. Over HTTP a missing repo now answers the
54+ receive-pack advertisement with a Basic challenge so git prompts.
55+ Verified e2e over both HTTP and SSH, incl. the cross-namespace denial.)_
56+- [x] make SSH the default clone selection in the clone pill buttons, and put
57+ it first (before HTTP) _(only when `[ssh] enabled`; HTTP stays the lone
58+ pill otherwise)_
3159 - [x] rename the `anvil` crate to `anvil_cli` _(named it `anvil-cli` to match
3260 the workspace's hyphenated crate names; the binary is still `anvild`, so
3361 deploy scripts and docs needed no changes)_
⋯ 51 unchanged lines
85113
86114 # Session notes / resume point
87115
88-_Last updated: 2026-06-10 (second session). Working state is clean: `cargo
89-build`, `cargo clippy --workspace`, `cargo fmt --all`, and `cargo test
90---workspace` all pass. Everything below is UNCOMMITTED (repo convention:
91-commit only when asked). **All top-of-file TODO items are done.**_
116+_Last updated: 2026-06-10 (third session). Working state is clean: build,
117+clippy, fmt, sort-derives, and `cargo test --workspace` all pass (the
118+pre-commit hook runs all of these). Third-session work below is UNCOMMITTED
119+(repo convention: commit only when asked). **All top-of-file TODO items are
120+done** except the pull-mirror "maybe"._
92121
93-## Done this session (2026-06-10, second session)
122+## Done this session (2026-06-10, third session)
94123
124+All six remaining TODO items — see the checked-off entries at the top of this
125+file for the details. Headlines:
126+
127+- **CI artifacts** (`docs/ci-artifacts.md` is the canonical reference):
128+ `artifacts:` in `.anvil/ci.yml`; broker pulls them out of the stopped
129+ container via `download_from_container` (inverse of the checkout upload —
130+ still no mounts); meta extractors run *inside* the sandbox, one file per
131+ value under `/tmp/anvil-meta`; `browse: true` directories are served like
132+ pages (rustdoc-ready); `/{owner}/{repo}/artifacts/{rev}/{name}` is the
133+ latest-on-branch alias; per-repo quota GC pins branch tips. New table
134+ `ci_artifacts` + `[ci] artifact_*_mb` caps.
135+- **Schema shims for existing DBs** (`anvil-core/src/db.rs`): Toasty still
136+ only pushes schema on a fresh file, so new tables/columns ship as
137+ idempotent DDL applied on connect (`SCHEMA_SHIMS`/`COLUMN_SHIMS`), with
138+ tests asserting fresh and migrated databases converge. New deps: rusqlite
139+ (pinned to toasty's), flate2.
140+- **Issues** (`anvil-core/src/issues.rs`, `anvil-web/src/issues.rs`):
141+ minimal GitHub-shaped tracker; tables `issues` + `issue_comments`.
142+- **Push mirroring** (`anvil-git/src/mirror.rs`): `repositories.mirror_url`
143+ → background `git push --mirror` after each push; Dockerfile now installs
144+ git (the one thing gix can't do yet is push).
145+- **Push-to-create** (`repos::create_on_push` + both transports), **README
146+ on repo page**, **SSH-first clone pills**, **rev-switcher/browse-at-rev UI**
147+ (committed earlier this session, along with the `anvil-cli` rename).
148+
149+## Done earlier (2026-06-10, second session)
150+
95151 - **UI quick wins** (`crates/anvil-web/src/ui.rs`) — latest-commit bar on the
96152 repo page (sha + subject + author/time, attached above the file box, links
97153 to the commit); profile page no longer shows the email; repo header reads
⋯ 59 unchanged lines
157213 - **CSRF header consumption:** `hx-headers` sends the token as a `csrf` header,
158214 but `verify_csrf` only reads the form field. When we add a tokenless htmx
159215 action (raw `hx-post`/`hx-delete`, no `<form>`), also read the `csrf` header.
160-- **Toasty migrations:** schema only pushed on a fresh DB (`db::connect`); new
161- columns won't apply to an existing DB until migrations land. (The
162- `data_dir/csrf_secret` file is created automatically — no DB change.)
163-- **Suggested commits when ready:** (1) CI UI, (2) CD webhook + deploy wiring,
164- (3) ci.rs ORM cleanup + test, (4) CSRF + cookies, (5) UI quick wins
165- (latest-commit bar, profile email, breadcrumb), (6) CI sandbox + threat-model
166- doc, (7) pages hosting. Trailer: `Co-Authored-By: Claude ...`.
216+- **Toasty migrations:** still no real migration system; the shim approach in
217+ `db::connect` (`SCHEMA_SHIMS` for tables, `COLUMN_SHIMS` for columns, both
218+ test-verified against a fresh `push_schema`) covers what we've needed so
219+ far. New columns must be declared last in the model.
220+- **Mirror URL secrecy:** `repositories.mirror_url` may embed a token and is
221+ stored plaintext in SQLite (logged redacted). Fine single-tenant; revisit
222+ if the DB ever leaves the box.
167223 - **Pages caveats (single-tenant-acceptable):** served from the forge origin —
168224 move to a separate origin before untrusted users (threat model §2); whole
169- blobs load into memory per request (fine at our scale).
225+ blobs load into memory per request (fine at our scale). The same applies to
226+ `browse: true` CI artifacts.
227+- **Issue tracker minimalism:** no labels, assignees, milestones, or
228+ editing/deleting of posts. Per-repo numbering assumes a single server
229+ process (matches deployment; noted in `models.rs`).
170230
171231 ## Remaining roadmap (plan milestones beyond a/b/c)
172232
173-8. Issues · 9. Pull requests (gix merge) · 10. Webhooks (mind the SSRF item).
233+9. Pull requests (gix merge) · 10. Webhooks (mind the SSRF item).
234+(8. Issues shipped 2026-06-10.)