- infra/scripts/simulate-two-host/: real two-Docker-network simulation (Gateway genuinely isolated from any Lab bridge network) proving the Lab Host Router fix - 13/13 real assertions (HTTP+WebSocket through the Router, Alice/Bob isolation, garbage/destroyed tokens, mTLS-only Router access). - infra/scripts/drills/: Lab Host loss/rebuild (9/9), deployment rollback, CI-fails-closed (6 required failure modes), fake cohort dress rehearsal (14/14, one continuous narrative through the real app). - infra/ci/gitea-workflows/build-and-test.yml: new security-scan job (npm audit, gitleaks, hadolint, shellcheck, trivy - all free/open-source), severity policy in docs/SECURITY_SCANNING.md (CRITICAL/HIGH blocks, MEDIUM/LOW reported only). Gates build-images alongside regression. Found and fixed two real pre-existing bugs via the CI-fails-closed drill: staging-smoke-test.sh and production-smoke-test.sh both had a classic set -e gotcha (curl ... && echo "OK" as one statement - a failing command that isn't last in an && chain doesn't trigger -e) that let an unreachable/broken endpoint fall through silently instead of failing the smoke test. platform/test/e2e-phase3a.js updated for the new paginated /api/admin/audit-events response shape (Phase 4.1 pagination work).
2.8 KiB
2.8 KiB
Security Scanning (Phase 4.1 §24)
infra/ci/gitea-workflows/build-and-test.yml's security-scan job. All free, open-source,
no account/signup required for any of them — no paid scanner was added.
What's scanned
| Tool | Checks | Scope |
|---|---|---|
npm audit --audit-level=high |
Known-vulnerable dependencies | Every first-party Node service |
| gitleaks | Committed secrets (keys, tokens, credentials) | Whole repo |
| hadolint | Dockerfile best-practice/security lint | Every first-party Dockerfile |
| shellcheck | Shell script correctness/security | infra/**/*.sh |
| trivy | OS/library CVEs in a built container image | platform-api image (representative — same base/layers as the other Node services) |
Severity policy
- CRITICAL / HIGH — fails the build (
security-scanblocksbuild-images, which blocksdeploy-staging, which blocks production promotion — see the job dependency chain in the workflow file). - MEDIUM / LOW — reported in the job output, never blocks. A build that's permanently red over a low-severity transitive dependency finding nobody can immediately fix trains everyone to ignore red builds, which is worse than not scanning at all.
npm audit --audit-level=high and trivy's --severity HIGH,CRITICAL both implement this
directly at the tool level, not via manual triage.
What's NOT in the automated job (and why)
- Dedicated IaC security linting (checkov/tflint) — not added.
infra/scripts/validate-compose.sh,infra/firewall/validate-firewall.sh,ansible-playbook --syntax-check, andtofu validate(all in theregressionjob) already catch structural/syntax problems in the infra code; a dedicated security-policy linter for Terraform/Ansible is a reasonable Phase 5 addition once there's a real cloud footprint to misconfigure, not before. - DAST/penetration testing — out of scope for CI; this is a build-time gate, not a running-system
test. Covered separately by
docs/PRODUCTION_VALIDATION_CHECKLIST.md's security section once real hardware exists. - SAST beyond hadolint/shellcheck — the codebase is small enough (a handful of first-party
Node services) that
npm audit+ secret scanning + Dockerfile/shell lint cover the realistic risk surface; a dedicated SAST tool (Semgrep, CodeQL) is a reasonable addition once the codebase or team grows enough to justify the added CI time.
Local reproduction
Every check above can be run locally with the exact same free tools — no CI-only dependency.
See the security-scan job's steps in infra/ci/gitea-workflows/build-and-test.yml for the
exact commands (they're copy-pasteable).