anvilsign in

collin/anvil

BoardRenderedSource

Tasks4 open

  1. don't expose a users email on their profile page
  2. don't include anvil before the breadcrumbs in the repo name i.e. anvil/collin/repo just do collin/repo
  3. implement github action style CI feature (core done — see "Session notes" below; the "isolated workers" idea is the (c) sandboxed broker, still TODO)
    • I want to get this to a sufficient state that we could bootstrap this app using this CI and automate deployments if we wished
    • probably might want to have other isolated anvil workers or something running for CI jobs
  4. implement github pages style hosting feature
  5. security audit (started: see (b) threat-model below)

Session notes / resume point6 open

  1. Done this session
    • CI UI — runs list /{owner}/{repo}/ci, run-detail (status/timing/log), per-commit status badges, "CI" nav link. (crates/anvil-web/src/ui.rs)
    • CD redeploy webhook — on a green run of [ci] deploy_branch in the single [ci] deploy_repo, POST to [ci] deploy_webhook (X-Anvil-Deploy-Secret header). Scoped to ONE repo. CiConfig in crates/anvil-core/src/config.rs; deploy() in crates/anvil-ci/src/lib.rs. Docs: DEPLOY.md §7, deploy/anvil.toml. reqwest added with NO TLS feature (keeps musl cross-compile aws-lc-free).
    • Docker socket on hagrid — deploy/run.sh mounts it + --group-adds the gid for the non-root user; caveat in DEPLOY.md §4.
    • Toasty ORM cleanup — ci.rs list_by_repo/latest_for_commit/ queued_ids now sort/limit/filter in SQL, not in memory. Verified by the new ordering_and_limit_run_in_the_database test. (Sweep: these were the only real instances; repos::list_all_with_owner sorts by a joined username and needs all rows — intentionally left.)
    • (a) CSRF + cookie hardening —
      • Cookie: HttpOnly + SameSite=Lax + Secure (auto via Config::secure_cookies() when base_url is https).
      • Synchronizer token HMAC-SHA256(server_secret, session); secret persisted at data_dir/csrf_secret (App::csrf_token in crates/anvil-core/src/lib.rs). Deps hmac, sha2.
      • Csrf extractor + constant-time verify_csrf (crates/anvil-web/src/auth.rs). Hidden csrf field + verification on add/delete SSH key, new repo, repo settings. Login exempt; logout relies on SameSite.
      • htmx insurance: auth::csrf_context middleware → request-scoped task-local; layout sends the token via hx-headers on every htmx request.
  2. Next up (the agreed a/b/c plan — (a) done)
  3. (b) untrusted-mode threat-model doc ← START HERE

    Write docs/untrusted-mode.md (or SECURITY.md). Capture the severity-ranked analysis:

    1. CI runner = root-equiv RCE via Docker socket — the hard blocker; fix is (c).
    2. Stored XSS if we ever serve raw blobs → separate origin + text/plain + CSP.
    3. Git resource exhaustion (pack/decompression bombs, huge ref ads) → size/ storage quotas + timeouts.
    4. Open registration anti-abuse (email verify, rate limit, CAPTCHA, quotas, ban).
    5. Authorization granularity → collaborator roles + per-repo tokens / deploy keys.
    6. Webhook SSRF (when webhooks land) → block private IPs / metadata / localhost. Already-right: private repos 404 (no leak), reserved usernames + /-/, CI tar-upload (not bind-mount), single-repo CD gate, argon2, CSRF + Secure cookies. Recommendation to record: single-tenant/owner-operated stays the supported stance; untrusted is gated behind (c).
  4. (c) sandboxed CI broker

    Make anvil the only Docker client; the job container gets NO socket. Forbid bind mounts; --cap-drop=ALL, --security-opt=no-new-privileges, read-only rootfs, non-root uid, --pids-limit, mem/cpu caps, wall-clock timeout, egress limits, image allowlist + CI-minute quotas. Stronger tier: gVisor/Kata/Firecracker microVMs (this is the "isolated workers" idea from the list above). Current runner: crates/anvil-ci/src/lib.rs::execute.

  5. Loose ends
    • CSRF header consumption: hx-headers sends the token as a csrf header, but verify_csrf only reads the form field. When we add a tokenless htmx action (raw hx-post/hx-delete, no <form>), also read the csrf header.
    • Toasty migrations: schema only pushed on a fresh DB (db::connect); new columns won't apply to an existing DB until migrations land. (The data_dir/csrf_secret file is created automatically — no DB change.)
    • Suggested commits when ready: (1) CI UI, (2) CD webhook + deploy wiring, (3) ci.rs ORM cleanup + test, (4) CSRF + cookies. Trailer: Co-Authored-By: Claude ....
  6. Remaining roadmap (plan milestones beyond a/b/c)
    1. Issues · 9. Pull requests (gix merge) · 10. Webhooks (mind the SSRF item) · github-pages-style static hosting (your list item).