From 94241358819cec774ff159d3e13a940d14a0fb90 Mon Sep 17 00:00:00 2001 From: wshallwshall Date: Mon, 7 Sep 2026 15:56:48 -0500 Subject: [PATCH] docs(security): move the built gitleaks and SBOM jobs out of "Planned CI additions" (BACKLOG #1485) docs/SECURITY.md's supply-chain section listed both as planned work. Both are built: security.yml's `gitleaks` job is named `gitleaks (secret scan)`, which is a required context, and the `sbom` job builds three CycloneDX bills of materials. The same two bullets carried three further stale claims. They said the scan was kept in CI "rather than a per-author pre-commit hook" while .pre-commit-config.yaml pins one at v8.18.4; they described the scan as covering the full git history, which BACKLOG #1479 changed; and the list they sat under called pip-audit and bandit advisory when both are blocking and required. The section also told the reader to enable CodeQL through GitHub Advanced Security, which this public repository does not need. The new text states the scan's scope nowhere. It names the step that holds it and stops, because a second copy of that fact is what went false (SDS-3.5). tests/test_cutover_slug_rot.py's triage taxonomy cited the removed GHAS sentence by name, so it is updated in the same change rather than left pointing at a line that no longer exists. Not taken here: docs/Secure_Build_Scorecard_MEFOR.md says "gitleaks full-history" three times, one of them evidence for a graded signal. That file is a dated scoring snapshot whose re-score is an owner act, so #1485 names the three lines for whoever re-signs it. Co-Authored-By: Claude Opus 5 --- docs/BACKLOG.md | 36 +++++++++++++++++++++++++++ docs/SECURITY.md | 45 ++++++++++++++++++++++------------ tests/test_cutover_slug_rot.py | 4 ++- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 6d12eccf6..9c5463ae7 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -24617,3 +24617,39 @@ A PAR client on the relying-party side: POST the authorization parameters to the This row was **filed, not built**. Nobody has read the pinned requirement text against `flow.py` for this row's purposes, and no provider-support survey was run. The `na` ruling above is reported as the routing fact that makes this row necessary; this row does not re-derive it and does not depend on it being correct. + +## 1485. docs/SECURITY.md files the built gitleaks and SBOM jobs under Planned CI additions + +> ๐Ÿšง **Filed 2026-09-07 -- the doc fix ships in this PR.** Value **4/10** ยท Difficulty **1/10** ยท _quick win_. The "Supply-chain & CI security" section listed the `gitleaks` secret scan and the CycloneDX SBOM build under **Planned CI additions**. Both are built, and `gitleaks (secret scan)` is a required context. The same two bullets carried three further stale claims, each independently checkable and each corrected here. Per `CLOSING_SEAT["code"]` the banner flip on merge is the LANDER's. +> Verdict: build +> Research: none +> Closing-act: code + +**Cluster:** documentation honesty / security prose. **Priority:** P3. **Verdict:** build. +**Severity:** no deployment axis (sec. 0). Nothing here is engine behaviour, a shipped artifact, or PHI, so no deploying site would meet it. The cost falls on a reader of the security record: they are told a built control is planned, told the wrong scope for a required gate, and told a local hook does not exist when it does. + +**Measured 2026-09-07** at engine `4c68c28eb`, which was `origin/main`'s tip in the same run. + +### Five claims, and what the tree says + +| the claim, as it stood | what the tree says | +|---|---| +| **SBOM** is a planned CI addition | `security.yml`'s `sbom` job builds CycloneDX bills of materials for the Python engine and the VS Code extension, scores them with `sbomqs`, and uploads them; the `trivy` job adds the container image. ADR 0149 and `docs/SUPPLY-CHAIN.md` document it. | +| **Secret-history scan** is a planned CI addition | `security.yml` job `gitleaks`, `name: gitleaks (secret scan)`, and that exact string is listed in `.github/required-contexts.txt`. | +| the scan is "Kept in CI rather than a per-author pre-commit hook" | `.pre-commit-config.yaml` pins `repo: https://github.com/gitleaks/gitleaks`, `rev: v8.18.4`, hook id `gitleaks`. Both exist. | +| the scan runs "over the **full git history**" | BACKLOG #1479 scoped it with `--log-opts HEAD`. The reason lives once, on the scan step's own comment, and this ledger row does not restate it either. | +| **pip-audit** and **bandit** are advisory | Both job comments read `BLOCKING`, neither declares `continue-on-error`, and both context strings are in `.github/required-contexts.txt`. | + +A sixth line was stale in a different direction: the section told the reader to turn **CodeQL** on through GitHub Advanced Security "on a private repo". `.github/workflows/codeql.yml` has run here for months and this repository is public, so no licence is involved. `security.yml`'s own header already records that correction. + +### The fix + +`docs/SECURITY.md` now carries one list of what CI runs, with `gitleaks` and the SBOM job in it, and no "Planned CI additions" block. It states the scan's scope **nowhere**: it names the step that holds it and stops, because a second copy of that fact is what went false last time. The section closes with a short paragraph naming what it used to say, so a reader who absorbed the old text can recognise the shape rather than be silently overwritten. + +### One dependent edit, and why it was not left to drift + +`tests/test_cutover_slug_rot.py`'s triage taxonomy cited the removed sentence by name, as a KEEP example ("a true statement about GitHub's pricing"). Removing the sentence without that edit would have left a docstring citing a line that no longer exists. The retirement is recorded in its place. The ratchet count falls 39 to 38 against a ceiling of 41; `test_the_ratchet_is_not_slack` allows up to 8 slack, so the ceiling is deliberately left alone. + +### Not taken here, and it is the same fact + +`docs/Secure_Build_Scorecard_MEFOR.md` says "gitleaks full-history" in three places (lines 31, 58 and 93), one of them the evidence for signal 5 graded **Built -- Strong**. That evidence is now overstated by exactly the scope BACKLOG #1479 removed. It is **not edited here**: that file is a dated scoring snapshot ("Scored 2026-07-14, against HEAD") whose own convention is that re-scoring is an owner act, and it already carries a precedent blockquote flagging a correction for the next re-sign rather than folding it silently. Naming the three lines is the handoff; whoever re-signs the scorecard folds them. diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 98af2b1e5..b72cdcb1d 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -2026,26 +2026,41 @@ All knobs live in the `[auth]` section of `messagefoundry.toml` (the AD bind pas ## Supply-chain & CI security -Automated security scanning runs in CI (`.github/workflows/security.yml`), so it lives there -rather than in the per-author `messagefoundry check` gate: +Automated security scanning runs in CI ([`.github/workflows/security.yml`](../.github/workflows/security.yml)), +so the enforced set lives there rather than in the per-author `messagefoundry check` gate. Read that +workflow for what each job does and whether it blocks; +[`.github/required-contexts.txt`](../.github/required-contexts.txt) is the authority on which checks +branch protection requires. At least these run: - **pip-audit** โ€” audits the **committed lockfile** (`requirements.lock`) for known-CVE dependencies, - so the audit is reproducible rather than auditing a fresh latest-resolve (advisory for now). -- **bandit** โ€” Python SAST over `messagefoundry/` (advisory). + so the audit is reproducible rather than auditing a fresh latest-resolve. +- **bandit** โ€” Python SAST over `messagefoundry/`. +- **gitleaks** โ€” the secret scan, in the job named `gitleaks (secret scan)`. Its step is *Scan the ref + under test for secrets*, and that step's comment states the scan's scope and the reason for it. Read + it there; this page does not restate it. A `gitleaks` hook in + [`.pre-commit-config.yaml`](../.pre-commit-config.yaml) runs the same tool before a commit. That hook + is a local aid, not a second gate: a fresh clone lacks it until `pre-commit install` runs, and + `git commit --no-verify` skips it. +- **SBOMs** โ€” CycloneDX bills of materials for the Python engine, the VS Code extension, and the + container image, kept as build artifacts, so "are we exposed to CVE-X?" is answerable from a recorded + bill of materials rather than a fresh resolve. Advisory, and generated on a cron rather than per pull + request. How they are built, scored, and used: [SUPPLY-CHAIN.md](SUPPLY-CHAIN.md) and + [ADR 0149](adr/0149-multi-ecosystem-sbom-vex-and-sbom-quality-gate.md). - **Dependabot** (`.github/dependabot.yml`) โ€” weekly PRs for `pip` and `github-actions` updates. - A private vulnerability-disclosure policy lives at [`.github/SECURITY.md`](../.github/SECURITY.md). -Enable via **GitHub Advanced Security** in repo settings (they need GHAS on a private repo, so they -can't be added by file alone): **CodeQL** code scanning and **secret scanning** + push protection. - -**Planned CI additions:** - -- **SBOM** โ€” generate a CycloneDX SBOM (e.g. `cyclonedx-py`) from the committed lockfile in CI and keep it - as a build artifact, so "are we exposed to CVE-X?" is answerable from a recorded bill of materials rather - than a fresh resolve. -- **Secret-history scan** โ€” a `gitleaks` (or trufflehog) job over the **full git history** in CI, to - complement GHAS secret scanning above. Kept in CI rather than a per-author pre-commit hook, to match the - pip-audit/bandit stance (one enforced gate, not optional local tooling). +**CodeQL** runs from [`.github/workflows/codeql.yml`](../.github/workflows/codeql.yml). This repository +is public, so CodeQL is free here and needs no GitHub Advanced Security licence. GitHub's own **secret +scanning** and push protection are repository settings rather than files in the tree. Read the settings +for their current state; this page does not track them. + +**What this section used to say, named so a reader who believed it can recognise the shape.** Until +2026-09-07 it filed the gitleaks and SBOM jobs under "Planned CI additions", called pip-audit and bandit +advisory, and told the reader to turn CodeQL on through Advanced Security. Every job it named was already +built, and pip-audit and bandit had stopped being advisory. The gitleaks entry also said the scan was kept +in CI "rather than a per-author pre-commit hook", while that hook sat pinned in the same tree, and it +described the scan as covering the full git history, which BACKLOG #1479 changed. Corrected under +BACKLOG #1485. ### Dependency lockfile (DEP-1) diff --git a/tests/test_cutover_slug_rot.py b/tests/test_cutover_slug_rot.py index 13a711b78..eb0210241 100644 --- a/tests/test_cutover_slug_rot.py +++ b/tests/test_cutover_slug_rot.py @@ -29,7 +29,9 @@ test_threat_model_doc_drift, test_ui_csp_canary), and the "pre-cutover this said X" annotations added when the guards above were fixed. These describe the past accurately. * KEEP โ€” not about this repo: `docs/INSTALL-GUIDE.md` / `docs/VERSION-CONTROL.md` mean the ADOPTER's - own private repo; `docs/SECURITY.md`'s GHAS note is a true statement about GitHub's pricing. + own private repo. This list also named `docs/SECURITY.md`'s GHAS note, which was retired on + 2026-09-07 (BACKLOG #1485) because its ADVICE had gone stale on a public repo, not because the + pricing claim in it was rot. Its removal is why the count fell by one. * KEEP โ€” idiom: "the mirror image of" in PLAN-PHASE4-GROUP-COMMIT and test_ledger_check. * FIX โ€” present-tense claims that this repo is a mirror, or that a private source repo runs CI.