Skip to content

feat: container image, Fly.io config and deploy workflow (D10) - #12

Merged
makoydev merged 1 commit into
nextfrom
feat/40-deploy
Oct 5, 2026
Merged

makoydev merged 1 commit into
nextfrom
feat/40-deploy

Conversation

@makoydev

@makoydev makoydev commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Part of makoydev/vetted#40 (D10). Everything up to the deploy itself; the deploy needs Michael's Fly.io account (docs/DEPLOY.md, about 10 minutes).

Image Static binary on distroless static-debian13:nonroot, non-root, images pinned by digest
CI New job "Container image": builds it and smoke-tests it the way Fly runs it (non-root, audit log on a volume, audit verify, no values in logs)
Fly sin, 256 MB shared, stops when idle, 1 GB volume, /healthz check, Fly-Client-IP for rate limits. Mock only: no upstream ever configured
Deploy deploy.yml from main only; skips without FLY_API_TOKEN; smoke-tests the live URL
Docs docs/DEPLOY.md (Michael's steps), README live link + 3-minute demo path + 5-minute quickstart, ADR 0009

Evidence

  • Built and run locally (Michael started Docker): 9.97 MB image, user nonroot:nonroot; the demo returned Member <NRIC_1> on <PHONE_1> as what the model saw, upstream mock; page served with CSP; audit verify OK inside the container on the volume; 0 planted values in the container logs.
  • Fly config keys checked against docs.fly.io; volume ownership for non-root images is from Fly's community forum (secondary) and will be confirmed by the first deploy's smoke test.
  • Build log: two process slips (merge-helper race that refused safely; zsh echo mangling JSON in a local test).

If asked in an interview

The public demo runs in a tiny container with no shell, as a non-root user, on one small machine in Singapore that sleeps when nobody's using it, so it costs well under a dollar a month. It's mock-only by construction: the configuration never points at a paid model, so nothing a visitor sends can cost money. Every pull request builds the exact image and runs it the way the host will, and every deploy ends by testing the live site. The one step I couldn't do is creating the hosting account, because that needs the owner's card.

🤖 Generated with Claude Code

- Dockerfile: static Go binary on distroless static-debian13:nonroot,
  non-root, /data owned by that user; both base images pinned by digest.
  Built and run locally the way Fly will run it: 9.97 MB, placeholders
  only to the model, audit verify OK on the volume, no values in logs.
- CI job "Container image" builds and smoke-tests it on every PR.
- fly.toml: Singapore, 256 MB shared machine that stops when idle, 1 GB
  volume, /healthz check, Fly-Client-IP for rate limits. Mock only: no
  upstream is ever configured (ADR 0009).
- deploy.yml: from main only, skips without FLY_API_TOKEN, pinned
  flyctl action, smoke test against the live URL.
- docs/DEPLOY.md: the one-time steps only Michael can do. README: live
  link (once deployed), three-minute demo path, five-minute quickstart.
- Build log: merge-helper race (refused safely) and a zsh echo slip.

Part of makoydev/vetted#40 (deployment waits for Michael's Fly account)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@makoydev makoydev added ai-drafted Change drafted by Claude Code; reviewed and merged by a human ai-merged Merged into next by Claude Code after checks passed; Michael reviews next -> main labels Oct 5, 2026
@makoydev
makoydev merged commit c7c9995 into next Oct 5, 2026
8 checks passed
@makoydev
makoydev deleted the feat/40-deploy branch October 5, 2026 15:17
makoydev added a commit that referenced this pull request Oct 5, 2026
- Dockerfile: static Go binary on distroless static-debian13:nonroot,
  non-root, /data owned by that user; both base images pinned by digest.
  Built and run locally the way Fly will run it: 9.97 MB, placeholders
  only to the model, audit verify OK on the volume, no values in logs.
- CI job "Container image" builds and smoke-tests it on every PR.
- fly.toml: Singapore, 256 MB shared machine that stops when idle, 1 GB
  volume, /healthz check, Fly-Client-IP for rate limits. Mock only: no
  upstream is ever configured (ADR 0009).
- deploy.yml: from main only, skips without FLY_API_TOKEN, pinned
  flyctl action, smoke test against the live URL.
- docs/DEPLOY.md: the one-time steps only Michael can do. README: live
  link (once deployed), three-minute demo path, five-minute quickstart.
- Build log: merge-helper race (refused safely) and a zsh echo slip.

Part of makoydev/vetted#40 (deployment waits for Michael's Fly account)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-drafted Change drafted by Claude Code; reviewed and merged by a human ai-merged Merged into next by Claude Code after checks passed; Michael reviews next -> main

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant