-
Notifications
You must be signed in to change notification settings - Fork 0
ci: vendor governance-enforce — this repo was never in the A_BLOCK ruleset #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
yakimoto
wants to merge
7
commits into
main
Choose a base branch
from
ci/vendor-governance-enforce
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
d4f618d
ci: vendor governance-enforce (A_BLOCK secrets scan) — this repo was …
yakimoto 70ac4c9
ci: fall back to HEAD~1 when the push base SHA is unreachable (force-…
yakimoto e6e12ed
ci: scope NODE_AUTH_TOKEN to the install step; diff empty tree when H…
yakimoto 67d046c
fix(ci): the vendored A_BLOCK gate could report PASS having scanned n…
yakimoto 7cea87b
fix(ci): recover a force-push-orphaned diff base instead of narrowing…
yakimoto 8124645
style(ci): punctuation cleanup in the diff-base recovery comment
yakimoto 6cf0c37
fix(ci): the empty-tree fallback, not HEAD~1 — a partial scan is stil…
yakimoto File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| name: governance-enforce | ||
|
|
||
| # A_BLOCK gate: no-secrets-in-git / secrets-from-doppler / no-hardcoded-paths, enforced on the | ||
| # PR diff via the @wave-av/governance package (the org fan-out channel). Diff-scoped: blocks NEW | ||
| # violations without failing on legacy debt. Isolated install bypasses any min-release-age policy. | ||
| # The org ruleset `governance-a-block-enforce` requires this job's `enforce` check. | ||
| # | ||
| # VENDORED 2026-08-05 (claude-workstation#1624, E4 T4.9a). This repo was never in that ruleset's | ||
| # include list, because the list is 112 hand-maintained names and every one of them matches | ||
| # `wave-*`. A naming convention had silently become a security boundary: the repos that publish | ||
| # our npm packages — cli, sdk, adk, mcp-server, workflow-sdk — were the ones running with no | ||
| # A_BLOCK secrets scan at all. | ||
| # | ||
| # HARDENED 2026-08-05 (claude-workstation#1747), before any of the fan-out merged. The copy first | ||
| # vendored here could report PASS having examined nothing. Five fixes, each marked at its site | ||
| # below. A gate may not return a passing value for input it did not examine. | ||
| # | ||
| # DO NOT add this repo to `governance-a-block-enforce` until this check is observed green here. | ||
| # A required status check that never reports is a permanent deadlock, not a stricter gate. | ||
|
|
||
| on: | ||
| pull_request: | ||
| # A required check that never reports on an event the repo actually uses is a permanent | ||
| # deadlock, not a stricter gate. None of these repos runs a merge queue today; declaring | ||
| # `merge_group` costs nothing until one does, and closes that hole in advance. | ||
| merge_group: | ||
| push: | ||
| branches: [main, master] | ||
|
|
||
| permissions: | ||
| contents: read | ||
| packages: read | ||
|
|
||
| # FIX 4 — a cancelled push run's commits were scanned by NOBODY. Every push run diffs only its | ||
| # own before..HEAD range, so cancelling run N when run N+1 starts leaves N's commits permanently | ||
| # unexamined. PR runs are safe to supersede: each one re-diffs the whole branch against its base. | ||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} | ||
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | ||
|
|
||
| jobs: | ||
| enforce: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 10 | ||
| steps: | ||
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | ||
| with: | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | ||
| with: | ||
| node-version: "22" | ||
| - name: fetch governance enforcer (isolated install) | ||
| # FIX 1 — token scoped to THIS STEP. At job level it was also in scope for the step that | ||
| # executes the downloaded package, and for anything else the job ever grows. | ||
| env: | ||
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| set -euo pipefail | ||
| mkdir -p "$RUNNER_TEMP/gov" && cd "$RUNNER_TEMP/gov" | ||
| trap 'rm -f "$RUNNER_TEMP/gov/.npmrc"' EXIT | ||
| printf '@wave-av:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' > .npmrc | ||
| # FIX 2 — --ignore-scripts. npm runs preinstall/install/postinstall by default, so this | ||
| # step would execute dependency-authored code with the registry token in its environment. | ||
| # FIX 3 — exact pin, and 0.4.6 specifically. `^0.4.4` resolved to 0.4.4, whose file lister | ||
| # is `catch { return []; }` — ANY git error became zero files and rendered as | ||
| # `OK[enforce]: 0 changed file(s) scanned`. 0.4.6 fails closed on a git error instead. | ||
| # A caret is also a standing authorization for whatever is published next; a bump is now | ||
| # a visible commit in this file. | ||
| npm install @wave-av/governance@0.4.6 --no-save --no-audit --no-fund --ignore-scripts | ||
| - name: A_BLOCK enforce (secrets + hardcoded paths on the diff) | ||
| env: | ||
| PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} | ||
| MERGE_BASE_SHA: ${{ github.event.merge_group.base_sha }} | ||
| PUSH_BEFORE_SHA: ${{ github.event.before }} | ||
| run: | | ||
| set -euo pipefail | ||
| ENFORCE="$RUNNER_TEMP/gov/node_modules/@wave-av/governance/bin/enforce.mjs" | ||
| BASE="${PR_BASE_SHA:-}" | ||
| [ -n "$BASE" ] || BASE="${MERGE_BASE_SHA:-}" | ||
| [ -n "$BASE" ] || BASE="${PUSH_BEFORE_SHA:-}" | ||
| # FIX 5 — fail CLOSED, and do not settle for a PARTIAL range either. | ||
| # | ||
| # This previously fell back to `BASE=HEAD`, and `--changed HEAD` diffs HEAD against | ||
| # itself: an empty diff, zero files scanned, job green. | ||
| # | ||
| # `HEAD~1` is the obvious replacement and is ALSO wrong — it scans exactly one commit, | ||
| # so a five-commit push whose base is indeterminate would examine the last one and | ||
| # report a confident pass on the other four. A narrowed scan reported as a full pass is | ||
| # the same defect in a quieter costume. (This is wave-av/wave-rig's reasoning, already | ||
| # correct on its main; the fan-out copied the broken shape from elsewhere.) | ||
| # | ||
| # A base can also be PRESENT and still unusable: a force-push leaves | ||
| # `github.event.before` pointing at a commit this checkout no longer contains. | ||
| # | ||
| # So: no resolvable base of any kind → diff against the EMPTY TREE, which makes every | ||
| # tracked file read as added and scans the whole repo. Loud, never partial, never empty. | ||
| # (`--all` also exists in 0.4.6 and would do most of this, but it is documented as NOT | ||
| # covering the diff-scoped over-grant detectors. Routing through the diff path with an | ||
| # empty base keeps every detector in play.) | ||
| if [ -z "$BASE" ] || [ "$BASE" = "0000000000000000000000000000000000000000" ] \ | ||
| || ! git cat-file -e "$BASE^{commit}" 2>/dev/null; then | ||
| BASE="$(git hash-object -t tree /dev/null)" | ||
| echo "::warning::indeterminate diff base (root commit, branch creation, or unreachable before-sha) — scanning the full tree against the empty-tree object so no commit is skipped" | ||
| fi | ||
| echo "diffing against $BASE" | ||
| exec node "$ENFORCE" --changed "$BASE" | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔍 Empty-tree fallback turns the diff-scoped gate into a full-repo scan that will trip on legacy debt
The header states the gate is diff-scoped precisely so it "blocks NEW violations without failing on legacy debt" (lines 4-5). The new fallback makes every tracked file read as added, so any pre-existing hardcoded path or secret-shaped string anywhere in the repo will fail the job. On
pull_requestthis cannot happen (base.sha is always present and fetched), but on a force-pushed branch'spushto main, or a root commit, the job would fail for reasons unrelated to the pushed change. That is the intended "loud" behavior, but onpushto main it produces a red default-branch build that no one can fix without whitelisting legacy debt — consider whether the fallback should warn-and-scan-full instead of blocking on non-PR events.Was this helpful? React with 👍 or 👎 to provide feedback.