diff --git a/.github/required-checks.json b/.github/required-checks.json index d7843e7..76b9664 100644 --- a/.github/required-checks.json +++ b/.github/required-checks.json @@ -1,4 +1,4 @@ { - "required": ["quality", "tests", "security", "Analyze (python)"], - "decisional": ["quality", "tests", "security"] + "required": ["quality", "tests", "security", "docs-privacy", "Analyze (python)"], + "decisional": ["quality", "tests", "security", "docs-privacy"] } diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 4600eef..1f9bf0a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -103,8 +103,9 @@ single-source runners under `scripts/gates/` (see - **`tests`** — `discover_floors.py --run` (the standalone `# FLOOR` floors) then `pytest tests/`. - **`security`** — `bandit` over the tree. +- **`docs-privacy`** — private-marker scan over `docs/**`. -A fourth check, **`Analyze (python)`** (CodeQL), is **non-decisional**: SARIF +A fifth check, **`Analyze (python)`** (CodeQL), is **non-decisional**: SARIF upload is blocked on the free private tier, so it shows nominally red and is never a merge signal. Read the verdict on the **machine field** (`statusCheckRollup[].name` / `.conclusion`) filtered to diff --git a/CI_CD.md b/CI_CD.md index 9fd8e92..48d2d3c 100644 --- a/CI_CD.md +++ b/CI_CD.md @@ -21,10 +21,12 @@ flowchart TD PR --> Q["quality
ruff · compile · skills"] PR --> T["tests
auto-discovered module floors"] PR --> S["security
Bandit SAST"] + PR --> DP["docs-privacy
private-marker scan over docs/**"] PR --> CQ["Analyze (python)
CodeQL security-extended"] Q --> G{"All required checks green?
branch up to date?
no CodeQL alert ≥ High / Errors?"} T --> G S --> G + DP --> G CQ --> G G -- yes --> M(["Merge to main"]) G -- no --> X(["Merge blocked"]) @@ -49,6 +51,7 @@ but gets **none** of Layer B — until it is recreated, the workflows still *run | `ci.yml` | PR to `main`, push to `main` | `quality` | `ruff check` → `ruff format --check` → `doc-drift` (tracked docs — `scripts/gates/doc_drift_targets.tsv`) → `compileall -q skills` | | `tests.yml` | PR to `main`, push to `main` | `tests` | the auto-discovered module floors + `pytest tests/` (exit 0/1); the first non-zero exit fails the check | | `security.yml` | PR to `main`, push to `main` | `security` | Bandit SAST: `bandit -c pyproject.toml -r .` | +| `docs-privacy.yml` | PR to `main`, push to `main` | `docs-privacy` | private-marker scan over `docs/**`: `bash scripts/gates/docs-privacy.sh` | | `codeql.yml` | PR + push + weekly (Mon 06:00 UTC) | `Analyze (python)` | CodeQL `security-extended` — the analysis **runs** (content gate is the Layer-B ruleset, below) | | `release.yml` | push of a tag `v*` | `release` | package the `.skill` deliverable + attach it to a Release; a version guard aborts if the tag ≠ the artifact's `metadata.version` | | `action-drift.yml` | weekly (Mon 06:00 UTC) + manual dispatch | `drift` (detector, not a gate) | re-checks the SHA-pinned action versions against upstream tags; opens an issue on drift — never edits a workflow, never blocks a merge | @@ -119,7 +122,7 @@ Configured via `gh api` (METHOD §7/§10) and recreated in any fork that wants t protection. **Branch protection on `main`:** require a PR; require status checks -`quality, tests, security, Analyze (python)`; require branches up to date; block force +`quality, tests, security, docs-privacy, Analyze (python)`; require branches up to date; block force pushes; restrict deletions; **do not allow bypassing (admins included)**. **Code-scanning ruleset** (targeting `main`): require code-scanning results, tool **CodeQL**, @@ -169,6 +172,7 @@ nothing **blocks** a merge — the blocking comes from Layer B. | `quality` required check | B (branch) | broken lint / format / compile | | `tests` required check | B (branch) | a failing skill floor | | `security` required check | B (branch) | a Bandit finding | +| `docs-privacy` required check | B (branch) | a private-marker leak into `docs/**` | | `Analyze (python)` required check | B (branch) | a CodeQL analysis failure (the run, not an alert) | | Code-scanning ruleset (CodeQL ≥ High / Errors) | B (ruleset) | a CodeQL **alert** (the finding) | | Secret scanning + push protection | B (Adv. Security) | a secret at push time | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index accdc5c..2439b54 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ This guide is for two audiences: ## Ground rules `main` is the protected trunk: every change is meant to land through a pull request that -passes the required checks (`quality`, `tests`, `security`, `Analyze (python)`). +passes the required checks (`quality`, `tests`, `security`, `docs-privacy`, `Analyze (python)`). Honest note on enforcement: on this repository's current tier, the **Layer-B** settings that *enforce* the rule (branch protection + the code-scanning ruleset) are **defined in files but @@ -72,7 +72,7 @@ Notes: flowchart LR F["Fork or branch"] --> L["Run gates locally
ruff · bandit · compile · floors"] L --> PR["Open a PR to main"] - PR --> C{"quality · tests · security · Analyze (python)
all green? branch up to date?"} + PR --> C{"quality · tests · security · docs-privacy · Analyze (python)
all green? branch up to date?"} C -- yes --> M(["Squash-merge"]) C -- no --> Fix["Fix and push again"] Fix --> C @@ -86,6 +86,7 @@ flowchart LR - **`quality`** — ruff lint + format, projected-doc drift (`doc-drift`), and the `compileall` sweep over `skills/`. - **`security`** — Bandit security scan. - **`tests`** — the auto-discovered module floors plus `pytest tests/`. + - **`docs-privacy`** — private-marker scan over `docs/**`. - **`Analyze (python)`** — CodeQL semantic security analysis. 6. Your branch must be **up to date with `main`** before merging. 7. Once Layer B is active, a merge is also blocked if CodeQL reports a code-scanning alert