From 2d50c7b51511d5cef99a0ff341121f261f90c88f Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Fri, 12 Jun 2026 22:08:29 -0400 Subject: [PATCH] docs(roadmap): add Phase 16 (CI dep audit, security & image hygiene); fold in + remove backlog 999.17 --- .planning/ROADMAP.md | 55 ++++++++++--------- .planning/STATE.md | 2 + .../.gitkeep | 1 + .../.gitkeep | 0 4 files changed, 33 insertions(+), 25 deletions(-) create mode 100644 .planning/phases/16-ci-dependency-audit-and-security-checks/.gitkeep delete mode 100644 .planning/phases/999.17-define-enforce-the-dev-prod-boundary-in-shipped-images/.gitkeep diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 62fcfa0..26ee958 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -3,7 +3,7 @@ ## Milestones - βœ… **v1.0 MVP** β€” Phases 1–6 (shipped 2026-06-10) β€” see [`milestones/v1.0-ROADMAP.md`](milestones/v1.0-ROADMAP.md) -- 🚧 **v1.1 Operability & Polish** β€” Phases 7–15 (planning) β€” mobile test harness, Gitea CI (runs the harness), faster write-back, in-app admin, per-event reminders, guided setup, real lint gate, desktop e2e, doc-only CI skip + markdown lint +- 🚧 **v1.1 Operability & Polish** β€” Phases 7–16 (planning) β€” mobile test harness, Gitea CI (runs the harness), faster write-back, in-app admin, per-event reminders, guided setup, real lint gate, desktop e2e, doc-only CI skip + markdown lint, CI dependency audit + security checks + image hygiene ## Phases @@ -21,7 +21,7 @@ Full phase detail archived in [`milestones/v1.0-ROADMAP.md`](milestones/v1.0-ROA -### 🚧 v1.1 Operability & Polish (Phases 7–15) +### 🚧 v1.1 Operability & Polish (Phases 7–16) Make FamilySync configurable, administrable, and maintainable for real multi-member use β€” without hand-editing env files or the database. The new critical path runs **mobile test harness β†’ Gitea CI** (CI consumes the harness specs for UI regression), and the **admin role β†’ reminders / setup wizard** chain (a single `/api/admin` + `/api/setup` route surface carrying the v1.1 DB migration). Faster write-back is a fully independent track. @@ -34,6 +34,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem - [x] **Phase 13: Real Lint Gate (ESLint)** - Wire ESLint flat config (typescript-eslint + React) across both apps so the Phase 8 CI lint slot actually fails on violations instead of no-op'ing (completed 2026-06-12) - [x] **Phase 14: Desktop E2E Coverage** - Add a Desktop Chrome Playwright profile + make the mobile-authored specs desktop-safe so the Phase 8 regression gate validates desktop, not just mobile (completed 2026-06-12) - [x] **Phase 15: Doc-Only CI Skip + Markdown Lint** - Aggregate-gate the slow api/harness CI jobs so doc-only PRs to main merge without running them (no branch-protection deadlock), and add markdownlint to `fast-checks` so docs get a fast format+lint gate (promoted from backlog 999.17) (completed 2026-06-12) +- [ ] **Phase 16: CI Dependency Audit, Security Checks & Image Hygiene** - Extend Gitea CI with outdated-dependency reporting + vulnerability audit + a baseline of additional security checks, and enforce the dev/prod image boundary so no dev-bypass, secret, or family data ships in published images (absorbs backlog 999.17); independent of the admin chain ## Phase Details @@ -305,6 +306,32 @@ Plans: **UI hint**: no +### Phase 16: CI Dependency Audit, Security Checks & Image Hygiene + +**Goal**: The CI pipeline surfaces outdated and vulnerable dependencies, runs a baseline of additional security checks, and enforces a clean dev↔prod boundary in the images it publishes β€” so the two-person household app doesn't silently rot on stale/CVE-bearing packages, and no dev-only affordance, secret, or family-specific data ever ships in a production image. Extends the existing Gitea CI (Phase 8) workflow with dependency/security/image-hygiene gates rather than standing up a separate pipeline. **Absorbs backlog 999.17 (dev/prod image boundary).** +**Mode:** standard +**Depends on**: Phase 8 (Gitea CI β€” adds steps to the existing workflow + publish job; no admin-chain dependency). Independent of Phases 10–12. +**Requirements**: TBD (define during discuss/plan β€” likely new `CI-*` / `SEC-*` IDs) + +**Candidate scope (to be sharpened in `/gsd-discuss-phase 16`):** + + - **Outdated dependencies:** a CI step that reports dependencies behind their latest (e.g. `pnpm outdated -r`), surfaced on the PR. Decide gating vs advisory, and how to handle the pinned-version table in CLAUDE.md (the stack pins exact versions β€” "outdated" must not fight intentional pins). + - **Vulnerability audit:** `pnpm audit` (or equivalent) against the lockfile, failing on a chosen severity threshold (e.g. high/critical). Decide the threshold and an allowlist/waiver mechanism for unfixable transitive advisories. + - **Additional security checks (user is open to these β€” pick a sensible baseline, avoid over-build):** candidates β€” secret scanning on the diff (gitleaks/trufflehog), a CodeQL/`eslint-plugin-security` static pass, dependency-review on PRs, Dockerfile/image scan (e.g. trivy) of the published image. + - **Dev/prod boundary definition & enforcement (from 999.17):** the `DEV_AUTH_BYPASS` concept (and any dev-only affordance) must be provably confined to local dev β€” never to production, never baked into published images. Today the guard is runtime-only (`NODE_ENV !== 'production' && DEV_AUTH_BYPASS === 'true'` in `apps/api/src/auth/devBypass.ts`); add (a) explicit documentation of what "dev image" vs "shipped image" means, and (b) build-time / boot-time enforcement (a `production` image refuses to boot β€” or the build aborts β€” if dev-bypass is enabled) as defense-in-depth. + - **No data/secrets in published images (from 999.17):** audit the Dockerfile(s) + the Phase 8 publish job (`publish.yml`) to confirm `.env`, dev seed SQL, local DB dumps, encryption keys, OIDC secrets, the `DEV_USER` seed, and family-specific fixtures are `.dockerignore`d and never `COPY`'d. Add a CI assertion that fails the publish if a dev-bypass code path is active, a forbidden env/secret is present, or personal/seed data is staged into the image context. The dev-stack seed path (`DEV_USER` id 1 + sample calendar/list data) must be unreachable from the production image/compose. + - **Noise control:** these gates are notorious for flaky/advisory-churn failures; decide blocking-on-merge vs warn-only per check, and where results surface (PR annotation vs job log), mirroring Phase 15's gate-aggregation approach. + +**Boundary:** Extends the existing Gitea CI workflow + publish job; does not remove dev-bypass (still needed for local verification and the Phase 7/8 harness) and does not add a new external service or a runtime dependency to the app. Automated dependency *upgrades* (e.g. Renovate/Dependabot bots) are a separate concern β€” decide in discuss whether they're in scope or deferred. + +**Plans**: 0 plans (run `/gsd-plan-phase 16` to break down) + +Plans: + +- [ ] TBD (run `/gsd-discuss-phase 16` then `/gsd-plan-phase 16`) + +**UI hint**: no + ## Progress | Phase | Milestone | Plans Complete | Status | Completed | @@ -324,6 +351,7 @@ Plans: | 13. Real Lint Gate (ESLint) | v1.1 | 3/3 | Complete | 2026-06-12 | | 14. Desktop E2E Coverage | v1.1 | 1/1 | Complete | 2026-06-12 | | 15. Doc-Only CI Skip + MD Lint | v1.1 | 3/3 | Complete | 2026-06-12 | +| 16. CI Dep Audit, Sec & Img Hyg | v1.1 | 0/? | Not started | - | ## Backlog @@ -513,26 +541,3 @@ Plans: Plans: - [ ] TBD (promote with /gsd-review-backlog when ready) - -### Phase 999.17: Define & enforce the dev/prod boundary in shipped images β€” dev-bypass and personal data must never reach production artifacts (BACKLOG) - -**Goal:** [Captured for future planning] The `DEV_AUTH_BYPASS` concept (and any other dev-only affordance) must be provably confined to local dev β€” never to production, and never baked into the Docker images CI builds and publishes. Today the guard is runtime-only (`NODE_ENV !== 'production' && DEV_AUTH_BYPASS === 'true'` in `apps/api/src/auth/devBypass.ts`), which is correct but relies on env discipline at deploy time. There is no enforced, documented line between the dev image and the shipped image. Equally important: **none of the operator's data or family-specific context** (seeded dev DB rows, real Fastmail emails, app passwords, encryption keys, OIDC secrets, the dev `DEV_USER`, local `.env` values) may be embedded in published images. - -**Options / decisions to make when picking this up:** - -- **Define the boundary explicitly:** document what "dev image" vs "shipped/prod image" means β€” which env vars, build args, seed data, and code paths are dev-only β€” and make it a referenceable convention (e.g. a `docs/dev-vs-prod.md` + a note in CLAUDE.md / deployment docs). -- **Build-time enforcement, not just runtime:** consider compiling out or hard-failing on dev-bypass in prod builds (e.g. build arg / env assertion at image build that aborts if `DEV_AUTH_BYPASS` is set, or a startup guard that refuses to boot a `production` image with bypass enabled). Today the only guard is the runtime conditional β€” a defense-in-depth build/boot check is missing. -- **No data/secrets in images:** audit the Dockerfile(s) and CI publish job (Phase 8 / `publish.yml`) to confirm `.env`, dev seed SQL, local DB dumps, encryption keys, and family-specific fixtures are `.dockerignore`d and never `COPY`'d. Verify the published image is data-free and seed-free. -- **CI assertion:** add a check in the publish pipeline that fails the build if a dev-bypass code path is active, a forbidden env/secret is present, or personal data is staged into the image context. -- **Dev-only seed isolation:** the host-side dev stack seeds `DEV_USER` (id 1) + sample calendar/list data; ensure that seed path is unreachable from the production image and compose. - -**Boundary:** This is about the dev↔prod artifact boundary and image hygiene, not about removing dev-bypass (it is needed for local verification and CI harness runs per Phases 7/8). The runtime guard stays; this adds definition, documentation, build/boot enforcement, and a CI safety net. - -**Context:** Raised 2026-06-12 during Phase 10 (Admin Role & Settings) discussion β€” `DEV_USER`/dev-bypass surfaced as the head of the admin chain (first-login-wins bootstrap), prompting the concern that the dev/prod line is under-defined and that no operator/family data should ever ship in CI-built images. Tags: ci, docker, security, dev-bypass, secrets, data-hygiene, deployment. - -**Requirements:** TBD -**Plans:** 0 plans - -Plans: - -- [ ] TBD (promote with /gsd-review-backlog when ready) diff --git a/.planning/STATE.md b/.planning/STATE.md index a04e620..f47407d 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -172,6 +172,8 @@ Recent decisions affecting current work: - Backlog reviewed (2026-06-10, /gsd-review-backlog): removed 6 stale duplicates (999.2/3/6/7/8/9 β€” already promoted into Phase 6) from the Backlog section + deleted the 999.2 dir; kept 999.1/4/5/10/11/12/13; added 999.14 (Gitea CI, promoted from STATE pending todo); archived stale kickoff-new-project todo. - **v1.1 roadmap created (2026-06-10):** 6 phases (7–12), continuing v1.0 numbering. 17/17 requirements mapped, no orphans. Promotions: 999.13β†’Faster Write-Back (CAL-15), 999.10β†’Admin Role & Settings (ADMIN-01/02/03), 999.11β†’Setup Wizard (SETUP-01/02/03/04), 999.4β†’Per-Event Reminders (CAL-13/14 + NOTIF-04/05/06), 999.14β†’Gitea CI (CI-01/02), 999.12β†’Mobile Test Harness (TEST-01/02). The v1.1 DB migration (users.is_admin, calendar_events.reminder_lead_minutes, app_config) is folded into the Admin phase (per ARCHITECTURE.md ordering), not a standalone migration phase; the reminders + wizard phases consume it. Backlog 999.5 (self-service onboarding) and 999.1 (provider abstraction) stay deferred β€” ADMIN-01 covers the admin-managed credential gap in the interim. - **v1.1 roadmap reordered (2026-06-10):** same 6 phases / 17 mappings, new order/numbering. Phase 7 = Mobile Test Harness (was 12), Phase 8 = Gitea CI (was 11), Phase 9 = Faster Write-Back (was 7), Phase 10 = Admin Role & Settings (was 8, carries the DB migration), Phase 11 = Per-Event Reminders (was 10), Phase 12 = Initial Setup Wizard (was 9). **Phase 8 (CI) scope extended:** the PR regression now also runs the Phase 7 mobile harness as a UI-regression step, bringing up the dev stack (API + PWA dev servers + MariaDB service container + DEV_AUTH_BYPASS) in the runner β€” so **Phase 8 now depends on Phase 7**. New critical path: **7 β†’ 8** (CI consumes the harness); **9** independent; **10 β†’ 11** and **10 β†’ 12** (admin migration precedes reminders + wizard). Parallelizable once prerequisites met: 9 anytime; 11 and 12 in parallel after 10; 7 then 8. +- **Phase 16 added (2026-06-12, /gsd-phase):** CI Dependency Audit, Security Checks & Image Hygiene β€” extend the Phase 8 Gitea CI workflow with outdated-dependency reporting (`pnpm outdated`), a vulnerability audit (`pnpm audit` at a chosen severity), and a baseline of additional security checks (secret scan / image scan). User requested a 16 integer phase (not a decimal insert) β€” they've been running independent/CI phases ahead of the admin chain. **Depends on Phase 8; independent of the admin chain (10–12).** Scope still needs definition β€” run /gsd-discuss-phase 16. Milestone window now Phases 7–16. +- **Backlog 999.17 folded into Phase 16 + removed (2026-06-12, /gsd-phase):** the dev/prod image-boundary item (confine `DEV_AUTH_BYPASS` to dev via build/boot-time enforcement; ensure no `.env`/secrets/encryption keys/`DEV_USER` seed/family data ship in published images; CI assertion in the publish job) was pulled into Phase 16 β€” shared CI surface and overlapping secret/image scanning made a separate phase redundant. The 999.17 backlog entry + its phase dir were **deleted** (not retained-for-history) since the scope now lives in an active phase; this also clears the recycled-number collision with Phase 15's historical "promoted from 999.17" provenance (the markdown-lint item that became Phase 15 had reused 999.17 first). ### Pending Todos diff --git a/.planning/phases/16-ci-dependency-audit-and-security-checks/.gitkeep b/.planning/phases/16-ci-dependency-audit-and-security-checks/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.planning/phases/16-ci-dependency-audit-and-security-checks/.gitkeep @@ -0,0 +1 @@ + diff --git a/.planning/phases/999.17-define-enforce-the-dev-prod-boundary-in-shipped-images/.gitkeep b/.planning/phases/999.17-define-enforce-the-dev-prod-boundary-in-shipped-images/.gitkeep deleted file mode 100644 index e69de29..0000000