Skip to content

Commit 40a6064

Browse files
nedtwiggclaude
andcommitted
Simplify SECURITY.md and security-audit.yaml
Five focused trims: - Cron-time bug: header callout said 07:13 UTC; the cron is 21 4 * * * (04:21 UTC). Match the doc to the code. - AUDIT_PAT pre-check heredoc compresses from 16 lines to 5; the failure report links back to SECURITY.md instead of inlining provisioning steps. - Define "agent-managed workflows" once near the top of GitHub Actions Policies, drop the parenthetical enumeration from the two later FAIL IFs that referenced it. - Audit prompt drops a duplicated $GH_TOKEN description and a redundant "available environment" trailer; same instructions in ~30 lines instead of ~50. - "Audit visibility" paragraph reduced from 4 sentences to 2 — the gap-resistant timestamp mechanism doesn't need to live in SECURITY.md, it's an implementation detail of the workflow. Net: -36 lines across the two files, same behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0eb0fda commit 40a6064

2 files changed

Lines changed: 35 additions & 71 deletions

File tree

.github/workflows/security-audit.yaml

Lines changed: 30 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,10 @@ jobs:
4949
env:
5050
AUDIT_PAT: ${{ secrets.AUDIT_PAT }}
5151
run: |
52-
if [ -n "$AUDIT_PAT" ]; then
53-
echo "AUDIT_PAT present."
54-
exit 0
55-
fi
52+
[ -n "$AUDIT_PAT" ] && exit 0
5653
echo "FAIL" > audit-status.txt
57-
cat > audit-report.md <<'EOF'
58-
## Summary
59-
60-
**Overall status: FAIL.** `AUDIT_PAT` is not present in the
61-
`security-audit` environment.
62-
63-
The audit refuses to run without `AUDIT_PAT`. It needs read-only
64-
`Administration`, `Secrets`, and `Environments` access to
65-
verify the ruleset, secret, and environment FAIL IFs.
66-
67-
Provision per `SECURITY.md` > CI Validation Contract: mint a
68-
fine-grained PAT scoped to this repository only, then run
69-
`gh secret set AUDIT_PAT --env security-audit --repo
70-
diffplug/dormouse`.
71-
EOF
72-
echo "::error::AUDIT_PAT secret is not set in the security-audit environment."
54+
echo "**FAIL** — \`AUDIT_PAT\` is not present in the \`security-audit\` environment. See [SECURITY.md > CI Validation Contract](https://github.com/$GITHUB_REPOSITORY/blob/main/SECURITY.md#ci-validation-contract) for provisioning." > audit-report.md
55+
echo "::error::AUDIT_PAT secret is not set."
7356
exit 1
7457
7558
- name: Audit against SECURITY.md
@@ -89,56 +72,37 @@ jobs:
8972
# writing audit-status.txt.
9073
claude_args: '--allowed-tools "Read,Write,Edit,Bash,Grep,Glob"'
9174
prompt: |
92-
You are auditing this repository against SECURITY.md. The
93-
specifications are concrete `FAIL IF` lines plus the
94-
explicit clause that the list is not exhaustive — any code
95-
change that creates a security hole or reveals an existing
96-
one should fail this job.
97-
98-
Process:
99-
1. Read SECURITY.md.
100-
2. For each `FAIL IF` line, identify the mechanical check
101-
(gh api, grep, file presence, running a script) and
102-
execute it. Record PASS or FAIL with concrete evidence
103-
— file path and line number, API response excerpt, or
104-
command output.
105-
3. After the FAIL IF list is exhausted, do a qualitative
106-
pass. Inspect `.github/workflows/`, `.config/tend.yaml`,
107-
`.github/dependabot.yml`, `scripts/`, and any code that
108-
references secrets, for security holes the specs don't
109-
cover.
110-
111-
`$GH_TOKEN` is the `AUDIT_PAT` — a fine-grained,
112-
read-only PAT scoped to Administration + Secrets +
113-
Environments. A previous workflow step has already verified
114-
the token is present, so you can assume it is. If `gh api`
115-
returns 403 / "Resource not accessible by integration" on
116-
any check, record that check as `FAIL` with a note that
117-
`AUDIT_PAT`'s scope has drifted from what SECURITY.md
118-
specifies — do not treat it as `UNVERIFIABLE`. Reserve
119-
`UNVERIFIABLE` for the rare case where an endpoint is
120-
genuinely indeterminable (e.g. a transient network error),
121-
and note explicitly why in the report.
122-
123-
Produce a Markdown report with three sections:
75+
Audit this repository against SECURITY.md. The `FAIL IF`
76+
lines are concrete checks; the spec also says the list is
77+
not exhaustive, so flag any other security hole you find.
78+
79+
For each `FAIL IF`, run the mechanical check (`gh api`,
80+
grep, file presence, or a script) and record PASS or FAIL
81+
with concrete evidence — file path and line number, API
82+
response excerpt, or command output. Then do a qualitative
83+
pass over `.github/workflows/`, `.config/tend.yaml`,
84+
`.github/dependabot.yml`, `scripts/`, and any code that
85+
touches secrets.
86+
87+
`$GH_TOKEN` is the `AUDIT_PAT` — a fine-grained, read-only
88+
PAT covering Administration + Secrets + Environments,
89+
guaranteed present by the previous step. If `gh api`
90+
returns 403 on any check, record FAIL with the note "PAT
91+
scope drifted from SECURITY.md"; reserve `UNVERIFIABLE`
92+
only for genuinely indeterminable cases (e.g. a transient
93+
network error) and explain why.
94+
95+
Write `audit-report.md` with three sections:
12496
- `## FAIL IF results` — one line per check with PASS/FAIL
125-
and concrete evidence
126-
- `## Qualitative findings` — free-form findings with
127-
severity (BLOCKER / WARNING / INFO)
97+
and evidence
98+
- `## Qualitative findings` — severity BLOCKER / WARNING / INFO
12899
- `## Summary` — overall PASS or FAIL with a one-paragraph
129100
rationale
130101
131-
Write the report to `audit-report.md` in the workspace.
132-
Write `PASS` or `FAIL` (no other text, no newline required)
133-
to `audit-status.txt`. Status is FAIL if any `FAIL IF` is
134-
violated or any qualitative finding is BLOCKER severity.
135-
Do not call `exit`; the next workflow step inspects the
136-
status file and surfaces the result.
137-
138-
Available environment: `$GH_TOKEN` is the workflow's
139-
GitHub token (read repo, write issues), `$GITHUB_REPOSITORY`
140-
is `owner/name`. Use `gh api` for GitHub configuration
141-
queries (rulesets, secrets, environments, collaborators).
102+
Write `PASS` or `FAIL` (no other text) to `audit-status.txt`.
103+
Status is FAIL if any `FAIL IF` is violated or any
104+
qualitative finding is BLOCKER. Do not call `exit` — the
105+
workflow inspects the status file.
142106
143107
- name: Surface result, file or close issue
144108
if: always()

SECURITY.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Security
22

3-
> **Audited automatically.** This spec is checked against the repository by [`security-audit.yaml`](.github/workflows/security-audit.yaml) on a 24-hour schedule (07:13 UTC) and as a required gate before every VS Code release. Each failure is filed as an issue labeled [`security-audit-failure`](https://github.com/diffplug/dormouse/issues?q=is%3Aissue+label%3Asecurity-audit-failure) — open ones are live, closed ones are the historical record of what tripped past audits and what changed to clear them.
3+
> **Audited automatically.** This spec is checked against the repository by [`security-audit.yaml`](.github/workflows/security-audit.yaml) on a 24-hour schedule (04:21 UTC) and as a required gate before every VS Code release. Each failure is filed as an issue labeled [`security-audit-failure`](https://github.com/diffplug/dormouse/issues?q=is%3Aissue+label%3Asecurity-audit-failure) — open ones are live, closed ones are the historical record of what tripped past audits and what changed to clear them.
44
55
Dormouse is a terminal, so users trust it with shells, source trees, credentials, and local files. The dependency graph and release pipeline is part of the product's security boundary.
66

@@ -23,7 +23,7 @@ New npm package versions are not adopted immediately. The workspace uses pnpm's
2323

2424
GitHub Actions are always pinned by commit hash, not version tag. Dependabot will update the hashes as necessary.
2525

26-
The agent-managed workflows (`tend-*.yaml`, `workflow-audit.yaml`, and `security-audit.yaml`) are exempt from the two rules below because they run Claude-powered automation that requires modifying issues, PRs, or code, or fetching an OIDC token. Their scope is bounded separately in the "Automated Maintainer" section.
26+
**Agent-managed workflows** are `tend-*.yaml`, `workflow-audit.yaml`, and `security-audit.yaml`. They implement the repo's automation and self-audit infrastructure, and are exempt from the two rules below because they need to modify issues, PRs, or code, or fetch an OIDC token. Their bounded scope is defined in the "Automated Maintainer" section.
2727

2828
- FAIL IF `pull_request_target` appears in any `.github/workflows/**` file other than `tend-*.yaml`.
2929
- FAIL IF a non-agent-managed workflow grants write permissions other than the explicitly scoped release provenance permissions `id-token: write` and `attestations: write`.
@@ -40,7 +40,7 @@ This repository runs the [tend](https://github.com/max-sixty/tend) agent harness
4040

4141
**Upstream compromise.** Tend's action is pinned by commit SHA (`max-sixty/tend@<sha>`) in every generated workflow, so silent updates to the running setup are not possible. `uvx tend@latest` runs only at install and during nightly regen; a compromise of that path would affect the next re-run, not the in-flight workflows.
4242

43-
**Audit visibility.** `workflow-audit.yaml` is a nightly job that walks every commit touching `.github/workflows/` since its previous successful run (using the GitHub API's timestamp as the lower bound, so a failed run pushes the window forward rather than dropping commits). It opens an issue summarizing each commit's author, refs, and changed files. A bot push that adds a new workflow file is visible in the next successful audit even if the bot tries to silently modify the audit workflow — the modification itself appears in the audit.
43+
**Audit visibility.** `workflow-audit.yaml` is a nightly job that walks every commit touching `.github/workflows/` since its previous successful run, opening an issue summarizing each. A bot push that disables or modifies the audit itself is caught in the next successful run's diff window.
4444

4545
- FAIL IF the repository ruleset named `Merge access` is missing, doesn't target `~DEFAULT_BRANCH`, blocks anything other than `update`, or doesn't have admin (`RepositoryRole` actor `5`) as its sole bypass actor.
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.
@@ -50,8 +50,8 @@ This repository runs the [tend](https://github.com/max-sixty/tend) agent harness
5050
- FAIL IF `AUDIT_PAT` is missing from the `security-audit` environment, or is present at the repo level instead. The audit refuses to run without it, and it must be env-scoped so a bot-pushed feature branch cannot reach it.
5151
- 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.
5252
- FAIL IF `.github/workflows/workflow-audit.yaml` is missing, disabled, or has not produced a successful run in the last 48 hours.
53-
- 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".
54-
- FAIL IF any agent-managed workflow (`tend-*.yaml`, `workflow-audit.yaml`, `security-audit.yaml`) grants a permission beyond `contents: write`, `pull-requests: write`, `issues: write`, `id-token: write`, `actions: read`, or any `read` permission.
53+
- FAIL IF any `tend-*.yaml` workflow uses an unpinned action reference (e.g. `@main`, no version). Tag pins are accepted inside `tend-*.yaml` because the file is owned by the upstream generator; every other workflow — agent-managed or not — must SHA-pin per the rule above.
54+
- FAIL IF any agent-managed workflow grants a permission beyond `contents: write`, `pull-requests: write`, `issues: write`, `id-token: write`, `actions: read`, or any `read` permission.
5555

5656
## VS Code Extension Releases
5757

0 commit comments

Comments
 (0)