Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions docs/BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25120,3 +25120,41 @@ The harm path is not "a reader is mildly misinformed". It is specific and it run
### Closing act

One docstring edit in `scripts/asvs/apply.py`, stating that the listed keys are the ones the writer ORDERS and that any other key is carried verbatim. Deliberately **no count** of the carried fields: a tally in a docstring goes stale silently, which is the same defect wearing a number.


## 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.

45 changes: 30 additions & 15 deletions docs/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2054,26 +2054,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)

Expand Down
4 changes: 3 additions & 1 deletion tests/test_cutover_slug_rot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Loading