From b67d757f871fa7d8aadad30448ee3f69902a86c2 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Sat, 13 Jun 2026 05:15:35 -0400 Subject: [PATCH] =?UTF-8?q?docs(16-01):=20complete=20boot-guard=20plan=20?= =?UTF-8?q?=E2=80=94=20add=20SUMMARY,=20advance=20state=20to=20plan=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .planning/ROADMAP.md | 6 +- .planning/STATE.md | 27 +++--- .../16-01-SUMMARY.md | 86 +++++++++++++++++++ 3 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 .planning/phases/16-ci-dependency-audit-and-security-checks/16-01-SUMMARY.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index d9bd10a..10ab211 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -328,7 +328,7 @@ Plans: Plans: **Wave 1** -- [ ] 16-01-PLAN.md — Image-hygiene runtime: bake NODE_ENV=production + boot-time refuse-to-boot guard (IMG-01) +- [x] 16-01-PLAN.md — Image-hygiene runtime: bake NODE_ENV=production + boot-time refuse-to-boot guard (IMG-01) - [ ] 16-02-PLAN.md — pnpm audit gate + waiver allowlist + advisory-only tiered outdated report (DEP-01, DEP-02) - [ ] 16-03-PLAN.md — Fold eslint-plugin-security into the lint gate as blocking errors + triage (SEC-02) - [ ] 16-04-PLAN.md — gitleaks config + full-history baseline + .dockerignore (SEC-01, IMG-02) @@ -359,7 +359,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/6 | Not started | - | +| 16. CI Dep Audit, Sec & Img Hyg | v1.1 | 1/6 | In Progress| | ## Backlog @@ -367,7 +367,7 @@ Plans: **Goal:** [Captured for future planning] Abstract the calendar backend behind a provider interface so Fastmail/CalDAV is one implementation among potentially many. Shipping with a single provider is fine, but the broker, sync, and event-expansion layers should be structured so additional providers (e.g. other CalDAV hosts, Google Calendar, generic ICS feeds) can be added without rework. Captures the "provider" seam as an explicit architectural concern. **Requirements:** TBD -**Plans:** 2/2 plans complete +**Plans:** 1/6 plans executed Plans: diff --git a/.planning/STATE.md b/.planning/STATE.md index fe6f86a..875e207 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.1 milestone_name: Operability & Polish status: executing -stopped_at: Phase 16 context gathered -last_updated: "2026-06-13T03:25:36.437Z" -last_activity: 2026-06-13 -- Phase 16 planning complete +stopped_at: Completed 16-01-PLAN.md +last_updated: "2026-06-13T09:15:26.256Z" +last_activity: 2026-06-13 -- Phase 16 execution started progress: total_phases: 19 completed_phases: 6 - total_plans: 17 - completed_plans: 17 + total_plans: 23 + completed_plans: 18 percent: 32 --- @@ -21,14 +21,14 @@ progress: See: .planning/PROJECT.md (updated 2026-06-10) **Core value:** One color-coded family calendar (shared + personal) and shared lists from a single low-friction PWA — cross-ecosystem, no app store -**Current focus:** Phase 09 — faster-write-back +**Current focus:** Phase 16 — ci-dependency-audit-and-security-checks ## Current Position -Phase: 13 -Plan: Not started +Phase: 16 (ci-dependency-audit-and-security-checks) — EXECUTING +Plan: 2 of 6 Status: Ready to execute -Last activity: 2026-06-13 -- Phase 16 planning complete +Last activity: 2026-06-13 -- Phase 16 execution started ### Deferred Checkpoint — Phase 15 Plan 15-03 Task 2 (human-action) @@ -103,6 +103,7 @@ _Updated after each plan completion_ | Phase 13-real-lint-gate-eslint P02 | 90 | 2 tasks | 31 files | | Phase 13-real-lint-gate-eslint P03 | 10 | 3 tasks | 399 files | | Phase 09-faster-write-back P01 | 341 | 3 tasks | 3 files | +| Phase 16 P01 | 188 | 3 tasks | 4 files | ## Accumulated Context @@ -164,6 +165,8 @@ Recent decisions affecting current work: - [Phase ?]: D-04-SCHEDULE-X-LOCATOR: Used .sx-react-calendar-wrapper CSS class to assert Schedule-X grid — no semantic role on outer wrapper div - [Phase ?]: D-04-EMPTY-NETWORK-SIM: Lists empty state simulated via page.route to 200 empty array — preserves seeded DB for parallel workers (D-06 / T-07-11) - [Phase ?]: D-13-08: Prettier reformat committed as isolated mechanical diff; CI Format check step added to fast-checks job +- [Phase ?]: D-07 (16-01): ENV NODE_ENV=production baked into production Dockerfile stage — engages devBypass.ts hard guard so DEV_AUTH_BYPASS never injects in production +- [Phase ?]: D-08 (16-01): assertNotDevBypassInProduction() boot guard — first statement in isMainModule(), exits non-zero when NODE_ENV=production AND DEV_AUTH_BYPASS=true; unit-tested ### Roadmap Evolution @@ -228,9 +231,9 @@ Recent decisions affecting current work: ## Session Continuity -Last session: 2026-06-13T02:50:57.477Z -Stopped at: Phase 16 context gathered -Resume file: .planning/phases/16-ci-dependency-audit-and-security-checks/16-CONTEXT.md +Last session: 2026-06-13T09:15:26.245Z +Stopped at: Completed 16-01-PLAN.md +Resume file: None ## Operator Next Steps diff --git a/.planning/phases/16-ci-dependency-audit-and-security-checks/16-01-SUMMARY.md b/.planning/phases/16-ci-dependency-audit-and-security-checks/16-01-SUMMARY.md new file mode 100644 index 0000000..af1b887 --- /dev/null +++ b/.planning/phases/16-ci-dependency-audit-and-security-checks/16-01-SUMMARY.md @@ -0,0 +1,86 @@ +--- +phase: 16-ci-dependency-audit-and-security-checks +plan: "01" +subsystem: api-security +tags: [security, boot-guard, docker, tdd] +dependency_graph: + requires: [] + provides: [assertNotDevBypassInProduction, bootGuards.ts, ENV NODE_ENV=production] + affects: [apps/api/src/index.ts, apps/api/Dockerfile] +tech_stack: + added: [] + patterns: [TDD RED/GREEN, process.exit spy, boot-time guard] +key_files: + created: + - apps/api/src/lib/bootGuards.ts + - apps/api/tests/lib/bootGuards.test.ts + modified: + - apps/api/src/index.ts + - apps/api/Dockerfile +decisions: + - "D-07: ENV NODE_ENV=production baked into production Dockerfile stage — engages devBypass.ts hard guard at image build time, not at runtime" + - "D-08: assertNotDevBypassInProduction() placed as first statement in isMainModule() — boot-time refuse-to-boot guard converts silent misconfig into loud exit(1)" + - "Guard evaluated at call time (not import time) — allows unit tests to set env vars before calling without module cache manipulation" +metrics: + duration_seconds: 188 + completed_date: "2026-06-13" + tasks_completed: 3 + files_changed: 4 +--- + +# Phase 16 Plan 01: Boot-time Dev-Bypass Guard Summary + +**One-liner:** Boot-time refuse-to-boot guard (`assertNotDevBypassInProduction`) plus `ENV NODE_ENV=production` baked into the production Dockerfile stage, turning a silent auth-bypass misconfiguration into an immediate non-zero exit. + +## What Was Built + +### Task 1 — RED (test commit 8414e89) +Created `apps/api/tests/lib/bootGuards.test.ts` with 3 test cases: +1. `NODE_ENV=production` + `DEV_AUTH_BYPASS=true` → `process.exit(1)` is called (spy throws to make it observable) +2. `NODE_ENV=development` + `DEV_AUTH_BYPASS=true` → no `process.exit` +3. `NODE_ENV=production` + `DEV_AUTH_BYPASS` unset → no `process.exit` + +Suite failed with `Cannot find module '../../src/lib/bootGuards.js'` — RED state confirmed. + +### Task 2 — GREEN (feat commit c2ffd1c) +- Created `apps/api/src/lib/bootGuards.ts` exporting `assertNotDevBypassInProduction(): void` +- JSDoc documents D-08, call-time env evaluation, and required placement rule +- Added import to `apps/api/src/index.ts` +- Added call as the **first** statement in `isMainModule()` block (before VAPID config, workers, serve()) +- 3/3 unit tests pass, `pnpm typecheck` green + +### Task 3 — Dockerfile ENV (chore commit 5b4f32a) +- Added `ENV NODE_ENV=production` to the `production` stage in `apps/api/Dockerfile` +- Placed between `WORKDIR /app/apps/api` and `COPY --from=pwa-builder` (exactly as specified) +- Comment references D-07 +- Exactly 1 occurrence; no other stage is affected + +## Deviations from Plan + +None — plan executed exactly as written. + +## TDD Gate Compliance + +- RED gate commit: `8414e89` — `test(16-01): add failing tests for boot-time dev-bypass guard` +- GREEN gate commit: `c2ffd1c` — `feat(16-01): add boot-time refuse-to-boot guard for dev-bypass in production` +- REFACTOR: not needed — implementation was clean on first pass + +## Threat Surface Scan + +No new network endpoints, auth paths, file access patterns, or schema changes introduced. The boot guard adds a startup-time process.exit — no new externally-reachable surface. + +## Known Stubs + +None. + +## Self-Check: PASSED + +- `apps/api/src/lib/bootGuards.ts` — FOUND +- `apps/api/tests/lib/bootGuards.test.ts` — FOUND +- `apps/api/src/index.ts` modified — assertNotDevBypassInProduction() called at line 115 +- `apps/api/Dockerfile` — `ENV NODE_ENV=production` present in production stage + +Commits: +- `8414e89` — test(16-01): add failing tests for boot-time dev-bypass guard +- `c2ffd1c` — feat(16-01): add boot-time refuse-to-boot guard for dev-bypass in production +- `5b4f32a` — chore(16-01): bake ENV NODE_ENV=production into production Dockerfile stage