11# Repo Health workflow verification
22
3- ` Repo Health ` is intentionally base-controlled. Its ` pull_request_target ` trigger supplies the
4- workflow definition from the target branch, and every checkout keeps the trusted base revision.
5- The PR head is fetched only as Git data. Never check out or execute PR-head code in that workflow.
3+ The github org blocks ` pull_request_target ` , so Repo Health is split in two:
4+
5+ - ` Repo Health ` (` squad-repo-health.yml ` ) runs on ` pull_request ` with a read-only token and no
6+ secrets. Every job checks out the PR's base commit and fetches the PR head only as Git data.
7+ Never check out or execute PR-head code there. It uploads one result file per scanner
8+ (` repo-health-{leakage,architectural,security} ` ).
9+ - ** Base-controlled only when the PR leaves ` squad-repo-health.yml ` unchanged.** A ` pull_request `
10+ run uses the workflow file from the PR merge commit, so a PR that edits that file controls every
11+ job of its own run, including the Bootstrap Protection check (it could make that job ` exit 0 ` ).
12+ The compensating control is code-owner review: ` .github/CODEOWNERS ` line 4 requests review from
13+ the code owners on every PR. As of 2026-11-07, ` dev ` 's rules require neither code-owner review
14+ nor any approval, and Bootstrap Protection is not a required check, so this control depends on
15+ reviewers reading workflow changes. Requiring code-owner review on ` dev ` would enforce it.
16+ - ` Repo Health Report ` (` squad-repo-health-report.yml ` ) runs on ` workflow_run ` from the default
17+ branch and holds the write token. It downloads each scanner's artifact by its exact name and
18+ treats the results as untrusted data: exact schema, size limit, one PR and head SHA across all
19+ results, bound to the ` workflow_run ` payload and the live PR, which must target ` dev `
20+ (` scripts/repo-health-report.mjs ` , ` scripts/workflow-run-pr-binding.mjs ` ). It posts only when
21+ the run's head commit holds the same ` squad-repo-health.yml ` blob as its merge base with ` dev ` .
22+ Both blobs are read by commit SHA, so a push after binding can't change the answer. Otherwise it
23+ logs a notice, posts no findings, and overwrites its own existing marker comments with a fixed
24+ notice naming the refused commit. Every posted comment names the head commit it describes.
25+
26+ Fork PRs from external contributors need a maintainer to approve their workflow runs first
27+ (` approval_policy: all_external_contributors ` ); nothing is posted before that.
628
729## Evidence levels
830
931- ** Shadow / non-authoritative:** ` Repo Health Shadow (Non-Authoritative) ` runs proposed scanners,
1032 reporter script bodies, and the reporter helper from the PR head under ` pull_request ` , a
1133 read-only token, no persisted checkout credentials, and fake Octokit. It can prove that proposed
1234 code compiles, preserves hostile text, and propagates API failures, but it cannot prove the
13- elevated production workflow has picked up the merged implementation.
35+ default-branch reporter has picked up the merged implementation.
1436- ** Post-merge / authoritative:** only a disposable PR opened after the change reaches ` dev ` and
15- observed through ` Repo Health ` proves the base-controlled writer now creates and cleans up its
16- marker comment.
37+ observed through ` Repo Health Report ` proves the default-branch writer now creates and cleans up
38+ its marker comment. A PR that changes ` squad-repo-health.yml ` itself never gets posted findings,
39+ so this canary is the only authoritative evidence for such a change.
1740
1841Do not weaken a scanner, add an exclusion, or change a finding merely to make the base-controlled
1942check on the implementation PR green.
@@ -46,18 +69,18 @@ PR_URL=$(gh pr create --base dev --title 'test: repo-health post-merge canary' \
4669PR_NUMBER=${PR_URL##*/ }
4770```
4871
49- Wait for ` Repo Health / Squad File Leakage ` , then verify exactly one authoritative marker and the
50- exact hostile filename:
72+ Wait for ` Repo Health ` and then ` Repo Health Report ` to complete , then verify exactly one
73+ authoritative marker, the exact hostile filename, and the head commit it describes :
5174
5275``` bash
5376EXPECTED=$( node --input-type=module -e \
5477 ' process.stdout.write(".squad/canary-`paired`-${-apostrophe-' \' ' -\"double quote\".md")' )
5578
56- gh api --paginate --slurp " repos/bradygaster /squad/issues/$PR_NUMBER /comments" \
79+ gh api --paginate --slurp " repos/github /squad/issues/$PR_NUMBER /comments" \
5780 > canary-comments.json
58- node --input-type=module - " $EXPECTED " << 'NODE '
81+ node --input-type=module - " $EXPECTED " " $( git rev-parse HEAD ) " << 'NODE '
5982import { readFileSync } from 'node:fs';
60- const expected = process.argv[2] ;
83+ const [ expected, head] = process.argv.slice(2) ;
6184const comments = JSON.parse(readFileSync('canary-comments.json', 'utf8')).flat();
6285const marked = comments.filter(({ body = '' }) =>
6386 body.includes('<!-- squad-repo-health-leakage -->'));
@@ -69,6 +92,9 @@ if (listed.length !== 1 || listed[0] !== `- \`${expected}\``) {
6992if (!marked[0].body.includes('Authoritative evidence')) {
7093 throw new Error('comment was not labeled authoritative');
7194}
95+ if (!marked[0].body.includes(`Results for head commit \`${head}\``)) {
96+ throw new Error(`comment does not name head commit ${head}`);
97+ }
7298NODE
7399rm canary-comments.json
74100```
@@ -80,8 +106,8 @@ git rm -- "$CANARY_PATH"
80106git commit -m ' test: clean up repo-health post-merge canary'
81107git push
82108
83- # After Repo Health / Squad File Leakage completes :
84- gh api --paginate --slurp " repos/bradygaster /squad/issues/$PR_NUMBER /comments" \
109+ # After Repo Health and Repo Health Report complete :
110+ gh api --paginate --slurp " repos/github /squad/issues/$PR_NUMBER /comments" \
85111 > canary-comments.json
86112node --input-type=module << 'NODE '
87113import { readFileSync } from 'node:fs';
@@ -95,6 +121,7 @@ gh pr close "$PR_NUMBER" --delete-branch
95121git switch dev
96122```
97123
98- Record the PR URL and both successful ` Repo Health ` run URLs in the implementing PR or issue.
99- This post-merge canary is the only authoritative evidence for a repo-health workflow/reporter
100- change; the pre-merge shadow remains intentionally non-authoritative.
124+ Record the PR URL and the successful ` Repo Health ` and ` Repo Health Report ` run URLs (both
125+ pushes) in the implementing PR or issue. This post-merge canary is the only authoritative evidence
126+ for a repo-health workflow/reporter change; the pre-merge shadow remains intentionally
127+ non-authoritative.
0 commit comments