feat(security): security-gate (gitleaks + pip-audit) before merge (ORCH-022) #67

Closed
admin wants to merge 0 commits from feature/ORCH-022-security-secret-scanning into main
Owner

Summary

  • Deterministic (no-LLM) security sub-gate on the deploy-staging -> deploy edge, run FIRST (before merge-gate ORCH-043 / image-freshness ORCH-058): cheap to fail before expensive rebase/rebuild; scans origin/main..HEAD before rebase so a task is never blamed for a CVE from an updated main.
  • gitleaks (offline secret-scan, pinned Go binary in Dockerfile) - fail-closed on tool error, so the "a secret always blocks" guarantee is unconditional.
  • pip-audit (OSV/PyPI dependency audit) - blocks at/over security_dep_block_severity (default HIGH); UNKNOWN/below -> warning; unreachable feed degrades fail-open + loud warning by default (strict via security_dep_audit_fail_closed).
  • Verdict lives ONLY in 17-security-report.md YAML frontmatter (write -> read-back = single source of truth); FAIL authoritative; missing/broken frontmatter -> fail-closed.
  • FAIL -> rollback to development + developer-retry (cap MAX_DEVELOPER_RETRIES); task_desc carries verbatim findings (ORCH-046). Self-hosting safe: only reads/scans/writes, never deploys/restarts prod.
  • Conditional rollout (security_gate_enabled + security_gate_repos; empty -> self-hosting only). STAGE_TRANSITIONS and DB schema unchanged.

Touch points

  • New leaf src/security_gate.py (never-raise) + check_security_gate in QG_CHECKS (lazy import) + _handle_security_gate wired FIRST in advance_stage deploy-staging block.
  • 6 ORCH_SECURITY_* settings (src/config.py, .env.example); pinned gitleaks in Dockerfile, pip-audit in requirements.txt, .gitleaks.toml at repo root.
  • Docs: docs/architecture/README.md (marked realized), CLAUDE.md (artifact 17), CHANGELOG.md.

Test plan

  • tests/test_security_gate.py - TC-01..TC-12
  • tests/test_qg_security.py - TC-13..TC-15
  • tests/test_stage_engine_security_gate.py - TC-16..TC-19, TC-21
  • TC-20: STAGE_TRANSITIONS unchanged; registry/edge snapshots green
  • Full suite: 772 passed

Refs: ORCH-022

Generated with Claude Code

## Summary - Deterministic (no-LLM) **security sub-gate** on the `deploy-staging -> deploy` edge, run **FIRST** (before merge-gate ORCH-043 / image-freshness ORCH-058): cheap to fail before expensive rebase/rebuild; scans `origin/main..HEAD` before rebase so a task is never blamed for a CVE from an updated `main`. - **gitleaks** (offline secret-scan, pinned Go binary in Dockerfile) - fail-closed on tool error, so the "a secret always blocks" guarantee is unconditional. - **pip-audit** (OSV/PyPI dependency audit) - blocks at/over `security_dep_block_severity` (default HIGH); UNKNOWN/below -> warning; unreachable feed degrades **fail-open + loud warning** by default (strict via `security_dep_audit_fail_closed`). - Verdict lives ONLY in `17-security-report.md` YAML frontmatter (write -> read-back = single source of truth); FAIL authoritative; missing/broken frontmatter -> fail-closed. - FAIL -> rollback to `development` + developer-retry (cap `MAX_DEVELOPER_RETRIES`); `task_desc` carries verbatim findings (ORCH-046). Self-hosting safe: only reads/scans/writes, never deploys/restarts prod. - Conditional rollout (`security_gate_enabled` + `security_gate_repos`; empty -> self-hosting only). `STAGE_TRANSITIONS` and DB schema **unchanged**. ## Touch points - New leaf `src/security_gate.py` (never-raise) + `check_security_gate` in `QG_CHECKS` (lazy import) + `_handle_security_gate` wired FIRST in `advance_stage` deploy-staging block. - 6 `ORCH_SECURITY_*` settings (`src/config.py`, `.env.example`); pinned gitleaks in `Dockerfile`, `pip-audit` in `requirements.txt`, `.gitleaks.toml` at repo root. - Docs: `docs/architecture/README.md` (marked realized), `CLAUDE.md` (artifact 17), `CHANGELOG.md`. ## Test plan - [x] `tests/test_security_gate.py` - TC-01..TC-12 - [x] `tests/test_qg_security.py` - TC-13..TC-15 - [x] `tests/test_stage_engine_security_gate.py` - TC-16..TC-19, TC-21 - [x] TC-20: `STAGE_TRANSITIONS` unchanged; registry/edge snapshots green - [x] Full suite: 772 passed Refs: ORCH-022 Generated with Claude Code
admin added 8 commits 2026-06-07 21:04:51 +03:00
Add a deterministic (no-LLM) security sub-gate on the deploy-staging -> deploy
edge, run FIRST (before merge-gate ORCH-043 and image-freshness ORCH-058) so it
fails cheaply before any expensive rebase/rebuild, and scans origin/main..HEAD
before rebase so a task is never blamed for a CVE introduced by an updated main.

Why: the autonomous pipeline merged branches into main with no check for a leaked
secret or a vulnerable dependency. For the self-hosting orchestrator (one shared
prod instance serving every project from a shared DB) a single leak/CVE landed in
the prod of all projects (CLAUDE.md self-hosting, section 8).

- New leaf src/security_gate.py (never-raise): gitleaks (offline, fail-closed on
  tool error => secrets guarantee is unconditional) + pip-audit (best-effort;
  unreachable CVE feed degrades fail-open + loud warning by default, strict via
  security_dep_audit_fail_closed). Verdict lives ONLY in 17-security-report.md
  YAML frontmatter (write -> read-back single source of truth); FAIL is
  authoritative; missing/broken frontmatter => fail-closed.
- check_security_gate thin wrapper registered in QG_CHECKS (lazy import, no cycle).
- _handle_security_gate wired FIRST in advance_stage deploy-staging block: FAIL ->
  rollback to development + developer-retry (cap MAX_DEVELOPER_RETRIES); task_desc
  carries verbatim findings (ORCH-046 pattern). No merge-lease release (runs before
  lease acquire). Self-hosting safe: only reads/scans/writes, never deploys.
- Conditional rollout (security_gate_enabled + security_gate_repos; empty scope ->
  self-hosting only). 6 new ORCH_SECURITY_* settings.
- Infra: pinned gitleaks Go binary in Dockerfile (+curl/ca-certificates), pip-audit
  in requirements.txt, versioned .gitleaks.toml at repo root.
- STAGE_TRANSITIONS and DB schema unchanged.

Docs: docs/architecture/README.md (marked realized), CLAUDE.md (artifact 17),
CHANGELOG.md. Tests: test_security_gate.py, test_qg_security.py,
test_stage_engine_security_gate.py + updated registry/edge snapshots.

Refs: ORCH-022

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
TC-17 seeded 17-security-report.md via get_worktree_path() which resolves to
settings.worktrees_dir (default /repos/_wt) -> the test wrote into the real shared
host worktree path. In CI that dir is owned by another user -> PermissionError.

Monkeypatch git_worktree.settings.worktrees_dir to tmp_path/_wt (same pattern as
test_git_worktree.py / test_merge_gate.py). Prod logic untouched.
tester(ET): auto-commit from tester run_id=331
All checks were successful
CI / test (push) Successful in 19s
CI / test (pull_request) Successful in 19s
8cdb9f194a
admin force-pushed feature/ORCH-022-security-secret-scanning from 0955ddd9fa to 8cdb9f194a 2026-06-07 21:04:51 +03:00 Compare
admin added 1 commit 2026-06-07 21:42:32 +03:00
deploy(ORCH-036): finalize SUCCESS for ORCH-022
All checks were successful
CI / test (push) Successful in 17s
CI / test (pull_request) Successful in 17s
e07ee9e574
admin added 1 commit 2026-06-07 22:24:32 +03:00
docs(ORCH-021): post-deploy HEALTHY/NONE for ORCH-022
All checks were successful
CI / test (push) Successful in 18s
CI / test (pull_request) Successful in 18s
0cbb7ef0bb
Author
Owner

Superseded by #71 (restore-main 2026-06-08): ORCH-022 code restored to main after phantom-merge.

Superseded by #71 (restore-main 2026-06-08): ORCH-022 code restored to main after phantom-merge.
admin closed this pull request 2026-06-08 10:55:32 +03:00
All checks were successful
CI / test (push) Successful in 18s
CI / test (pull_request) Successful in 18s

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/orchestrator#67