Files
familysync/.planning/milestones/v1.1-phases/16-ci-dependency-audit-and-security-checks/16-06-SUMMARY.md
T
2026-06-18 22:21:38 -04:00

4.7 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics, requirements
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics requirements
16-ci-dependency-audit-and-security-checks 06 ci
ci
docker
image-hygiene
boot-smoke
security
publish
requires provides affects
16-01
16-04
IMG-03
.gitea/workflows/publish.yml
added patterns
Static assertion step: grep-based structural checks in shell before docker push
Boot-smoke: docker run with forbidden env combo + timeout + exit-code semantics
created modified
.gitea/workflows/publish.yml
D-10 (16-06): Static assertions grep for 7 forbidden .dockerignore patterns + --target production pin; grep is substring-safe (apps/api/scripts matches apps/api/scripts/seed-credential.mjs)
D-10 (16-06): Boot-smoke treats EXIT==0 and EXIT==124 as failures; any other non-zero is a PASS — covers the D-08 guard's process.exit(1) path
D-10 (16-06): Both hygiene steps ordered strictly after build and before push; set -euo pipefail ensures any failure stops the job before push runs
duration completed tasks_completed files_modified
1 minute 2026-06-13 2 1
IMG-03

Phase 16 Plan 06: Image Hygiene CI Assertions Summary

One-liner: Publish-time CI assertions that block docker push when .dockerignore is incomplete, --target production is dropped, or the production image tolerates DEV_AUTH_BYPASS=true (D-10 / IMG-03).

What Was Built

Two CI assertion steps added to .gitea/workflows/publish.yml, inserted strictly between the Build production image step and the Push image step:

Step 1 — "Image hygiene — static assertions" (set -euo pipefail):

  • Fails if .dockerignore is absent
  • Loops over 7 forbidden patterns (.env, node_modules, apps/api/scripts, .git, .planning, apps/api/tests, apps/pwa/e2e) and fails if any is missing from .dockerignore
  • Fails if --target production is no longer grep-able in publish.yml itself
  • Catches config drift that would ship secrets or dev files (T-16-19)

Step 2 — "Image hygiene — boot-smoke (must refuse dev-bypass in production)" (set -euo pipefail):

  • Runs the freshly-built sha_tag image with NODE_ENV=production DEV_AUTH_BYPASS=true
  • timeout 15 caps the run (T-16-21: prevents the job hanging if the guard does not fire)
  • EXIT==0 → image started → guard NOT working → FAIL
  • EXIT==124 → timeout → guard not firing → FAIL
  • Any other non-zero exit → image refused boot → PASS
  • Proves assertNotDevBypassInProduction() (16-01 / D-08) fires in the actual shipped image (T-16-18)

The step order in the publish job is now:

  1. Checkout
  2. Compute image tags
  3. Docker login
  4. Build production image
  5. Image hygiene — static assertions ← new
  6. Image hygiene — boot-smoke ← new
  7. Push image
  8. Docker logout (if: always())

Task Commits

Task Name Commit Files
1 Split publish build and push into separate steps bc00f3e .gitea/workflows/publish.yml
2 Add static image-hygiene assertion + boot-smoke before push 27046db .gitea/workflows/publish.yml

Deviations from Plan

None — plan executed exactly as written.

Verification

  • YAML parses cleanly (python3 yaml.safe_load confirmed)
  • Step ordering verified: assertions at indices 4-5, push at index 6 (between Build at 3 and Push at 6)
  • All 7 forbidden .dockerignore patterns confirmed present in .dockerignore
  • --target production grep confirmed to match within publish.yml
  • Dockerfile ENV NODE_ENV=production confirmed in production stage (line 45) — precondition for the smoke to be meaningful
  • bootGuards.ts process.exit(1) confirmed fires when NODE_ENV=production AND DEV_AUTH_BYPASS=true — that is what the smoke exercises

Threat Coverage

Threat ID Description Mitigated By
T-16-18 Regressed image that tolerates DEV_AUTH_BYPASS=true published Boot-smoke step: fails push if image starts under forbidden combo
T-16-19 Future change removes .dockerignore or drops --target production Static assertions step: fails push on any missing pattern or pin
T-16-20 Assertions run after push (bad image already published) Ordering: both steps are before Push image step
T-16-21 Boot-smoke hangs if guard does not fire timeout 15; EXIT==124 treated as failure

Known Stubs

None.

Self-Check

Files modified:

  • .gitea/workflows/publish.yml — modified (confirmed by git log)

Commits:

  • bc00f3e — ci(16-06): split publish build and push into separate steps
  • 27046db — ci(16-06): add static image-hygiene assertion + boot-smoke before push

Self-Check: PASSED