ci(16-06): add static image-hygiene assertion + boot-smoke before push
- Static assertions step: verifies .dockerignore exists, covers all forbidden patterns (.env, node_modules, apps/api/scripts, .git, .planning, apps/api/tests, apps/pwa/e2e), and --target production is still pinned in publish.yml (T-16-19) - Boot-smoke step: runs freshly-built sha_tag image with NODE_ENV=production + DEV_AUTH_BYPASS=true; fails if image starts (EXIT==0) or times out (EXIT==124), passes on any other non-zero exit — proves D-08 guard fires in shipped image (T-16-18) - Both steps ordered after build and before push; a hygiene failure blocks publish (T-16-20)
This commit is contained in:
@@ -85,6 +85,60 @@ jobs:
|
||||
-t ${{ steps.tags.outputs.sha_tag }} \
|
||||
.
|
||||
|
||||
# ── D-10 image hygiene assertions — run AFTER build, BEFORE push ───────────
|
||||
# A failure here stops the job before any push, so a regressed image can
|
||||
# never be published (T-16-18 / T-16-19 / T-16-20).
|
||||
- name: Image hygiene — static assertions
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Assert .dockerignore exists
|
||||
if [ ! -f ".dockerignore" ]; then
|
||||
echo "FAIL: .dockerignore does not exist"
|
||||
exit 1
|
||||
fi
|
||||
# Assert every forbidden pattern is covered by .dockerignore
|
||||
for pattern in ".env" "node_modules" "apps/api/scripts" ".git" ".planning" "apps/api/tests" "apps/pwa/e2e"; do
|
||||
if ! grep -q "$pattern" .dockerignore; then
|
||||
echo "FAIL: .dockerignore missing pattern: $pattern"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
# Assert this workflow still pins --target production (D-10 / T-16-19)
|
||||
if ! grep -q "\-\-target production" .gitea/workflows/publish.yml; then
|
||||
echo "FAIL: publish.yml does not build --target production"
|
||||
exit 1
|
||||
fi
|
||||
echo "Static image hygiene assertions PASSED."
|
||||
|
||||
# Boot-smoke: run the freshly-built production image with the forbidden
|
||||
# NODE_ENV=production + DEV_AUTH_BYPASS=true combo and assert it refuses to
|
||||
# boot — proving the D-08 guard (assertNotDevBypassInProduction) fires in
|
||||
# the ACTUAL shipped image (T-16-18 / T-16-21).
|
||||
# EXIT==0 → image started → guard NOT working → FAIL
|
||||
# EXIT==124 → timeout (15s) → guard not firing → FAIL
|
||||
# Any other non-zero exit → image refused boot → PASS
|
||||
- name: Image hygiene — boot-smoke (must refuse dev-bypass in production)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
IMAGE="${{ steps.tags.outputs.sha_tag }}"
|
||||
set +e
|
||||
timeout 15 docker run --rm \
|
||||
--env NODE_ENV=production \
|
||||
--env DEV_AUTH_BYPASS=true \
|
||||
"$IMAGE" \
|
||||
2>&1 | head -20
|
||||
EXIT=$?
|
||||
set -e
|
||||
if [ "$EXIT" -eq 0 ]; then
|
||||
echo "FAIL: Production image started successfully with DEV_AUTH_BYPASS=true — guard not working"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$EXIT" -eq 124 ]; then
|
||||
echo "FAIL: Production image did not exit within 15s — guard not firing"
|
||||
exit 1
|
||||
fi
|
||||
echo "PASS: Production image refused to start with DEV_AUTH_BYPASS=true (exit $EXIT)"
|
||||
|
||||
# Push the IMMUTABLE :<milestone>-<sha> tag FIRST. set -euo pipefail stops on
|
||||
# the first failed push, so :latest is only moved after the immutable,
|
||||
# rollback-traceable tag has landed — a failed second push can never leave
|
||||
|
||||
Reference in New Issue
Block a user