anvilsign in

collin/anvil

BoardRenderedSource

1# Todo
2
3- [ ] pull mirror (maybe): a repo that virtually mirrors a GitHub repo
4 - just displays it here — periodically fetched, read-only on the anvil side
5- [ ] pull requests (gix merge)
6- [ ] webhooks (mind the SSRF item in `docs/untrusted-mode.md`)
7
8## Edit files in the web UI
9
10Edit a file in the browser and have anvil make a proper commit (author = the
11logged-in user, sensible message), written straight onto the branch with gix —
12no working tree. The new commit just advances the branch tip, so anyone who
13pushed earlier can fast-forward pull it.
14
15- [x] start minimal: an "Edit" button on the blob page → textarea → commit;
16 commits build the tree/commit objects via gix and move the ref (reject if the
17 branch moved under us — no non-fast-forward clobber). `anvil-git/src/edit.rs`
18 does the CAS commit; `ui.rs` `edit_form`/`edit_submit` wire the page.
19- [x] a structured way to add items to `TODO.md` — an "Add task" form that
20 appends a ticket (`## title`, the richer card style) to the right section per
21 the todo-md round-trip rules (`todomd::add_task` / `task_sections`), rather
22 than hand-editing the raw file
23- [ ] then richer editing: a real markdown editor with a live render preview
24 (reuse `render_markdown`) before committing
25
26## Image uploads (attachments stored outside git)
27
28Upload an image in the web editor and link to it from the markdown without the
29blob ever entering git history. Stored content-addressed per repo and served
30back; the file only carries the URL.
31
32- [x] store: content-addressed blobs at `data/attachments/{repo_id}/{sha256}`,
33 deduped per repo; `Attachment` model maps repo_id/hash → content-type, size,
34 uploader, created-at. Kept out of `repositories/` so it's never a git object.
35 (`anvil-core`: `attachments`, `storage::attachment_path`, schema shim.)
36- [x] serve: `GET /{owner}/{repo}/-/attachments/{hash}`, read-access gated
37 (private repos stay private), immutable cache + `nosniff` + locked-down CSP.
38- [x] upload: `POST /{owner}/{repo}/-/attachments` behind write-access + CSRF
39 (`X-CSRF-Token` header), magic-byte sniffed to png/jpeg/gif/webp (SVG
40 rejected), capped by `http.attachment_max_mb`, returns the markdown to splice.
41- [x] editor UX: paste or drop an image in the file editor → background upload →
42 `![image](url)` inserted at the cursor.
43- [x] caps: per-repo attachment quota (`http.attachment_quota_mb`, 0 =
44 unlimited) — a new upload over the cap is rejected; deduped re-uploads are
45 always free. (Reject, not evict: evicting would break live Markdown links.)
46- [ ] within-repo reclaim: an orphan sweep (delete attachments no committed file
47 references) and/or a per-attachment delete action — the recourse once a repo
48 hits its quota. Deferred: deletion is destructive and "orphaned" is fuzzy
49 (tip-only vs any-ref), so it wants its own design pass.
50- [ ] remove a repo's attachment + artifact dirs on repo delete — blocked: there
51 is no repo-delete path yet (only the create-rollback uses it).
52
53## Admin: site disk-usage dashboard
54
55- [x] `/-/admin/usage` (admin-only; 404 for everyone else, nav link for admins):
56 actual on-disk bytes per user, broken down by content type (repositories / CI
57 artifacts / attachments) with column + grand totals. `anvil-core::usage`
58 walks the stores; `storage::dir_size` sums them.
59- [ ] maybe: per-repo drill-down, and a cheap cached/periodic variant if the
60 on-demand disk walk gets slow on large instances.
61
62## API tokens (read-only PATs)
63
64- [x] `ApiToken` model + `anvil-core::api_tokens` (create/list/revoke, SHA-256
65 hashed, scoped). CLI `anvild user token create|list|revoke`.
66- [x] bearer auth: `CurrentUser` also accepts `Authorization: Bearer <pat>` on
67 GET/HEAD only — least-privilege read-only (writes need a session CSRF a bearer
68 lacks). Lets tooling (and Claude) fetch private-repo attachments over HTTP.
69 See the recipe in `CLAUDE.md`.
70- [x] token management on the user settings page (`/-/settings`): create (secret
71 shown once), list, and revoke — ownership-enforced.
72- [ ] maybe later: a `write` scope (would need CSRF-exempt write paths) and
73 `last_used_at` tracking.
74
75## UI polish (done)
76
77- [x] less vertical padding at the top of the screen (`main` top padding 24→12px)
78- [x] kanban card details: the disclosure toggle restyled to a clean uppercase
79 marker, and the expanded detail text is no longer de-emphasized (full `--fg`,
80 not muted)
81- [x] kanban card images constrained to the card width (`max-width:100%`); they
82 were rendering at natural size on the board while fine on the rendered page
83
84## implement delete task
85
86Implement delete task functionality from the todo.md editor.