Skip to content

Commit 48fabef

Browse files
nedtwiggclaude
andcommitted
Env-gate the security-audit so AUDIT_PAT can't be exfiltrated
Created the `security-audit` GitHub environment via API with deployment-branch-policies admitting only `main` and `v*` tags — both admin-gated by the §3 rulesets. The audit job now declares `environment: security-audit`, so a bot-pushed feature branch can't trigger the workflow at all (GitHub rejects the run before any step starts). When AUDIT_PAT is later minted, it goes into this environment rather than at the repo level, sealing it from any workflow the bot can author on a non-admin-gated ref. SECURITY.md: generalized the env deployment-branch-policy FAIL IF to cover all environments (today: vscode-extension-publish and security-audit). Added a FAIL IF asserting AUDIT_PAT must live in the environment, not at repo level. Added a paragraph to the CI Validation Contract explaining the env-gating. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent bddca07 commit 48fabef

2 files changed

Lines changed: 13 additions & 1 deletion

File tree

.github/workflows/security-audit.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ jobs:
2020
audit:
2121
runs-on: ubuntu-latest
2222
timeout-minutes: 20
23+
# The AUDIT_PAT (read-only Administration + Secrets + Environments)
24+
# lives in this environment, whose deployment-branch-policy admits
25+
# only `main` and `v*` tags — refs that the §3 rulesets reserve to
26+
# admins. A bot-pushed feature branch cannot reach this job at all
27+
# (GitHub rejects the run before any step starts), so the PAT
28+
# cannot be exfiltrated through a hand-authored workflow on a
29+
# non-admin-gated ref.
30+
environment:
31+
name: security-audit
2332
steps:
2433
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2534
with:

SECURITY.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ This repository runs the [tend](https://github.com/max-sixty/tend) agent harness
4646
- FAIL IF the repository ruleset named `Tag operations` is missing, doesn't target `~ALL` tags, doesn't block both `creation` and `update`, or doesn't have admin-only bypass.
4747
- FAIL IF `dormouse-bot` holds a permission higher than `push` on this repository.
4848
- FAIL IF `OVSX_PAT` or `VSCE_PAT` appears as a repo-level secret. They must live only in the `vscode-extension-publish` environment.
49-
- FAIL IF the `vscode-extension-publish` environment's deployment-branch-policies allow any ref pattern that is not admin-gated by the `Tag operations` or `Merge access` rulesets.
49+
- FAIL IF any GitHub environment's deployment-branch-policies admit a ref that is not admin-gated by the `Tag operations` or `Merge access` rulesets. Today this covers `vscode-extension-publish` (`v*` tag, admin-only via `Tag operations`) and `security-audit` (`main` admin-only via `Merge access`, plus `v*` tag).
50+
- FAIL IF `AUDIT_PAT` exists at the repo level. If the secret is provisioned at all, it must live in the `security-audit` environment so a bot-pushed feature branch cannot reach it.
5051
- FAIL IF `CHROMATIC_PROJECT_TOKEN` is missing from `secrets.allowed` in `.config/tend.yaml`. The allowlist entry is an explicit acknowledgment that the bot can read this token.
5152
- FAIL IF `.github/workflows/workflow-audit.yaml` is missing, disabled, or has not produced a successful run in the last 48 hours.
5253
- FAIL IF any `tend-*.yaml` workflow uses an unpinned action reference (e.g. `@main`, no version). Inside `tend-*.yaml`, both tag pins (`@v6`, `@0.0.25`) and SHA pins are accepted because the file is owned by the upstream generator (`max-sixty/tend`), which currently uses tag pins. All actions in every other workflow — including `workflow-audit.yaml` and `security-audit.yaml` — must follow the SHA-pin rule in "GitHub Actions Policies".
@@ -73,5 +74,7 @@ Desktop releases are not fully automated. GitHub Actions builds unsigned artifac
7374

7475
The `security-audit` workflow at `.github/workflows/security-audit.yaml` enforces this document. It runs nightly and is a required dependency of the VS Code publish job in `release.yml`, so no release ships without a passing audit. The audit reads SECURITY.md, executes each `FAIL IF` as a mechanical check, and also does a qualitative pass for security holes the specs don't cover. On any `FAIL IF` violation or BLOCKER-severity finding, the workflow opens (or updates) an issue labeled `security-audit-failure` with the full audit report, and exits non-zero. When a subsequent audit passes, the open failure issue is auto-closed so the tracker matches the live state.
7576

77+
The audit job declares `environment: security-audit`, whose deployment-branch-policy admits only `main` and `v*` tags. Both ref classes are admin-only by §3's rulesets, so a write-scoped bot cannot reach the env's secrets (most importantly `AUDIT_PAT`, when provisioned) by pushing a workflow file to a feature branch.
78+
7679
- FAIL IF `.github/workflows/security-audit.yaml` is missing, disabled, or no longer invoked from `release.yml`'s publish path.
7780
- FAIL IF the audit has been weakened — e.g. the prompt no longer requires the qualitative pass, a `FAIL IF` can be ignored, or the failure-reporting step that opens a `security-audit-failure` issue and exits non-zero has been removed.

0 commit comments

Comments
 (0)