docs(16-05): complete security job + gate wiring plan

This commit is contained in:
Lucas Berger
2026-06-13 08:25:00 -04:00
parent f0f7d8a9f4
commit 6e5086ce5e
3 changed files with 94 additions and 9 deletions
+3 -3
View File
@@ -335,7 +335,7 @@ Plans:
**Wave 2** *(blocked on Wave 1 completion)*
- [ ] 16-05-PLAN.md — Add the security job to ci.yml (gitleaks always; audit/outdated code-gated) + gate wiring (CI-03)
- [x] 16-05-PLAN.md — Add the security job to ci.yml (gitleaks always; audit/outdated code-gated) + gate wiring (CI-03)
- [ ] 16-06-PLAN.md — publish.yml static image-hygiene assertion + boot-smoke before push (IMG-03)
**UI hint**: no
@@ -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 | 4/6 | In Progress| |
| 16. CI Dep Audit, Sec & Img Hyg | v1.1 | 5/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:** 4/6 plans executed
**Plans:** 5/6 plans executed
Plans:
+9 -6
View File
@@ -3,14 +3,14 @@ gsd_state_version: 1.0
milestone: v1.1
milestone_name: Operability & Polish
status: executing
stopped_at: Completed 16-03-PLAN.md
last_updated: "2026-06-13T12:16:33.687Z"
stopped_at: Completed 16-05-PLAN.md
last_updated: "2026-06-13T12:24:49.646Z"
last_activity: 2026-06-13 -- Phase 16 execution started
progress:
total_phases: 19
completed_phases: 6
total_plans: 23
completed_plans: 21
completed_plans: 22
percent: 32
---
@@ -26,7 +26,7 @@ See: .planning/PROJECT.md (updated 2026-06-10)
## Current Position
Phase: 16 (ci-dependency-audit-and-security-checks) — EXECUTING
Plan: 5 of 6
Plan: 6 of 6
Status: Ready to execute
Last activity: 2026-06-13 -- Phase 16 execution started
@@ -107,6 +107,7 @@ _Updated after each plan completion_
| Phase 16-ci-dependency-audit-and-security-checks P02 | 25 | 3 tasks | 5 files |
| Phase 16-ci-dependency-audit-and-security-checks P03 | 2 | 2 tasks | 5 files |
| Phase 16 P04 | 45 | 4 tasks | 3 files |
| Phase 16 P05 | 7 | 2 tasks | 1 files |
## Accumulated Context
@@ -174,6 +175,8 @@ Recent decisions affecting current work:
- [Phase ?]: D-03-OBJ-INJECT: detect-object-injection disabled globally in eslint-plugin-security block — all hits were numeric loop indices / schema-derived keys; zod guards real API input; 14 of 15 rules remain at error
- [Phase ?]: D-04-ALLOWLIST: crypto.test.ts TEST_KEY allowlisted by path — human-verified Vitest beforeAll synthetic AES-256-GCM fixture; 4th [[allowlists]] block in .gitleaks.toml
- [Phase ?]: D-04-BASELINE: gitleaks full-history baseline is empty [] after allowlisting — 613 commits / 23 MB scanned clean; PR-diff scans in 16-05 start from provably clean state
- [Phase ?]: D-12-security-job: gitleaks runs unconditionally, pnpm audit/outdated code-gated at step level
- [Phase ?]: D-14-gate-security: security wired into gate with individual needs.security.result==success check (not success-or-skipped, Gitea #31007)
### Roadmap Evolution
@@ -238,8 +241,8 @@ Recent decisions affecting current work:
## Session Continuity
Last session: 2026-06-13T12:16:33.678Z
Stopped at: Completed 16-03-PLAN.md
Last session: 2026-06-13T12:24:49.635Z
Stopped at: Completed 16-05-PLAN.md
Resume file: None
## Operator Next Steps
@@ -0,0 +1,82 @@
---
phase: 16-ci-dependency-audit-and-security-checks
plan: "05"
subsystem: ci
tags: [gitea-ci, gitleaks, security, pnpm-audit, dependency-audit, gate]
dependency_graph:
requires: ["16-02", "16-03", "16-04"]
provides: ["security job in ci.yml", "gate wired with security check"]
affects: [".gitea/workflows/ci.yml"]
tech_stack:
added: []
patterns: ["security CI job parallel to fast-checks", "individual needs.X.result check (Gitea #31007)", "base.sha probe with git merge-base fallback"]
key_files:
modified:
- path: .gitea/workflows/ci.yml
role: CI workflow — security job added; gate aggregator updated
decisions:
- "D-12: gitleaks always runs on every PR via unconditional steps (no job-level if:); only pnpm audit/outdated are code-gated at step level"
- "D-14/D-15: security wired into gate with individual needs.security.result check — must be 'success', not 'success-or-skipped', because gitleaks always runs"
- "A2/OQ-1: base.sha probe step with git merge-base fallback guards against empty base.sha on some Gitea versions"
metrics:
duration: 7
completed: "2026-06-13T12:23:36Z"
tasks_completed: 2
files_modified: 1
---
# Phase 16 Plan 05: CI Security Job — Summary
**One-liner:** Dedicated `security` CI job (gitleaks always + audit/outdated code-gated) wired into the `gate` aggregator with an individual `needs.security.result` success check.
## What Was Built
A new `security` job was added to `.gitea/workflows/ci.yml`, placed between `harness` and `gate` in the file order (runs in parallel with `fast-checks`). The job:
- Runs on every PR (`if: github.event_name == 'pull_request'`), `needs: [changes]`
- Uses `actions/checkout@v4` with `fetch-depth: 0` (Pitfall 3 — base.sha must be locally present)
- Has a "Probe PR base/head SHA" step that reads `github.event.pull_request.base.sha` and falls back to `git merge-base origin/${{ github.base_ref }} HEAD` if empty (Assumption A2 / OQ-1), exporting `BASE_SHA` and `HEAD_SHA` to `$GITHUB_ENV`
- Installs gitleaks v8.30.1 from GitHub releases (pinned, no `actions/cache` per D-PROBE-04), then runs `gitleaks git --log-opts="--no-merges ${BASE_SHA}..${HEAD_SHA}" --config .gitleaks.toml --baseline-path scripts/gitleaks-baseline.json --exit-code 1` — both gitleaks steps have **no `if:`** (D-12: blocking on every PR)
- The pnpm setup-node / corepack / install / check-audit / check-outdated steps each carry `if: needs.changes.outputs.code == 'true'` (step-level, so gitleaks still runs on doc-only PRs)
The `gate` aggregator was updated:
- `needs:` expanded to `[fast-checks, changes, api, harness, security]`
- An individual `if [ "${{ needs.security.result }}" != "success" ]` check was inserted between the fast-checks check and the api/harness for loop
- Security is **not** folded into the for loop — it must always succeed (cannot be skipped)
## Commits
| Hash | Message | Files |
|------|---------|-------|
| 61b7586 | ci(16-05): add security job (gitleaks always; audit/outdated code-gated) | .gitea/workflows/ci.yml |
| f0f7d8a | ci(16-05): wire security job into gate aggregator | .gitea/workflows/ci.yml |
## Deviations from Plan
None — plan executed exactly as written.
The task described a "Probe PR base/head SHA" step as a separate explicit step (per PLAN.md acceptance criteria A2/OQ-1). This matches the PLAN.md requirement and was implemented accordingly. The PATTERNS.md skeleton showed a simpler inline version; the PLAN.md explicitly required the probe step with fallback, so the PLAN.md was authoritative.
## Threat Coverage
| Threat | Mitigation | Status |
|--------|-----------|--------|
| T-16-15 — secret introduced in PR diff | gitleaks runs unconditionally, gate blocks on non-success | Mitigated |
| T-16-16 — unwaived High/Critical advisory merges to main | check-audit.mjs code-gated, gate blocks | Mitigated |
| T-16-17 — gitleaks scans nothing (empty range) | fetch-depth:0 + base.sha probe + merge-base fallback | Mitigated |
| T-16-SC — gitleaks binary substitution | version pinned to 8.30.1 from gitleaks/gitleaks official releases | Accepted residual (no checksum) |
## Known Stubs
None.
## Threat Flags
None — this plan adds only CI workflow steps and does not introduce new network endpoints, auth paths, or schema changes.
## Self-Check: PASSED
- `.gitea/workflows/ci.yml` — FOUND
- Commit 61b7586 (add security job) — FOUND
- Commit f0f7d8a (wire gate) — FOUND
- `16-05-SUMMARY.md` — FOUND