Skip to content

ci: vendor governance-enforce — this repo was never in the A_BLOCK ruleset - #27

Open
yakimoto wants to merge 4 commits into
mainfrom
ci/vendor-governance-enforce
Open

ci: vendor governance-enforce — this repo was never in the A_BLOCK ruleset#27
yakimoto wants to merge 4 commits into
mainfrom
ci/vendor-governance-enforce

Conversation

@yakimoto

@yakimoto yakimoto commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Adds the governance-enforce A_BLOCK gate (secrets / hardcoded-paths, diff-scoped) to this repo. Part of claude-workstation#1624 E4 T4.9a, following the wave-av/cli#20 pilot.

Why this repo had no secrets scan

The org ruleset governance-a-block-enforce (17901847) requires an enforce check across the fleet. Its scope is an explicit include list of 112 hand-maintained repository names — and every one of them matches wave-*.

The 16 public repos absent from that list are exactly the 16 not named wave-*: .github, adk, api-spec, cli, companion-module-wave, create-wave-app, crest-console, dispatch-edge, examples, mcp-server, obs-wave-plugin, sdk, sdk-python, sdks, vmix-wave-integration, workflow-sdk.

Read the intersection: the repos that publish our npm packages are precisely the repos running with no A_BLOCK secrets scan. Nobody excluded them. A naming convention silently became a security boundary, and it drew the line in the worst possible place.

Why the workflow lands before the ruleset entry

Adding a repo to a required_status_checks ruleset before it emits that check is a permanent deadlock — a required check that never reports can never go green, and every PR on the repo becomes unmergeable. So the order is: vendor the workflow, observe it green, then extend the list. Doing it the intuitive way round would have bricked all sixteen.

This PR is also its own liveness drill. The workflow triggers on pull_request, so it runs on the PR that adds it. If enforce reports green here, the vendored shape works in this repo. If it does not, nothing was required and nothing is blocked — which is the point of this ordering.

Proven before fan-out, not assumed

@wave-av/governance is an internal-visibility package owned by claude-workstation, so whether a public repo's GITHUB_TOKEN can read it was the one real assumption. Rather than fan out on the inference, it was piloted on a single repo first:

wave-av/cli#20 — workflow run 31011943790, conclusion success.

That is the receipt this PR rides on. The shape is copied verbatim from wave-av/wave-moq-edge (public, 12/12 green), which matters because auto-approve.yml fails silently on every public repo — it calls a reusable workflow in the private wave-foundation, and a public repo cannot do that (parse-time failure, zero jobs, no annotation). This workflow calls nothing cross-repo, so that trap does not apply.

Security properties, unchanged from the source:

  • actions SHA-pinned (actions/checkout@df4cb1c, actions/setup-node@48b55a0)
  • persist-credentials: false on checkout
  • least privilege: contents: read + packages: read
  • isolated install into RUNNER_TEMP, --no-save, so nothing touches this repo's dependency tree
  • the .npmrc is written with a literal ${NODE_AUTH_TOKEN} (single-quoted printf) which npm expands at run time — no secret value is ever written to disk or a log
  • both ${{ }} inputs (base.sha, event.before) are routed through env: and read as "$VAR", never interpolated into the script body

Diff-scoped by design: it blocks new violations without failing on legacy debt.

Refs wave-av/claude-workstation#1624.


View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.


Note

Low Risk
CI-only change with no application runtime impact; it tightens supply-chain hygiene around the enforcer install and fail-closed scanning behavior.

Overview
Adds governance-enforce, a new GitHub Actions workflow that runs the org A_BLOCK gate on PRs and pushes to main/master via @wave-av/governance@0.4.6 (secrets-in-git, Doppler expectations, hardcoded paths), diff-scoped so only new violations fail.

The enforcer is installed in an isolated $RUNNER_TEMP tree with --ignore-scripts, registry auth limited to the install step, SHA-pinned actions, and packages: read only. Diff base resolution is hardened: invalid or missing bases fall back to HEAD~1, then to the empty tree so the job cannot pass with zero files scanned; push runs use concurrency so superseded runs do not leave commits unexamined.

The workflow is intentionally not wired into the org ruleset until this check is green here, avoiding a required check that never reports.

Reviewed by Cursor Bugbot for commit 31eeb1c. Configure here.

Review in cubic

Note

Add governance enforcement workflow to scan diffs on PRs and pushes to main

Adds governance-enforce.yml, which runs @wave-av/governance@0.4.6 on pull requests, merge groups, and pushes to main/master. The enforcer scans only changed files using a computed diff base; if no valid base is found, it falls back to the empty tree and scans the full repository. Push and merge group runs are not cancelable to ensure no committed ranges are skipped.

Macroscope summarized d0277f0.

@yakimoto yakimoto added the rr:skip-cubic RF.P1 reviewer routing (#1039) label Aug 5, 2026
@cursor

cursor Bot commented Aug 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_acffa972-9cef-43ca-8492-c256cba1317d)

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 44 minutes

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fb2a5d95-0a75-4359-ae4c-93da74007e63

📥 Commits

Reviewing files that changed from the base of the PR and between a5e2253 and d0277f0.

📒 Files selected for processing (1)
  • .github/workflows/governance-enforce.yml

Comment @coderabbitai help to get the list of available commands.

@macroscopeapp

macroscopeapp Bot commented Aug 5, 2026

Copy link
Copy Markdown

Approvability

Verdict: Approved d0277f0

New CI workflow adding governance/secrets enforcement, authored by the designated CODEOWNER. Unresolved review comments are verification suggestions or appear stale rather than substantive bugs. Standard CI configuration addition.

You can customize Macroscope's approvability policy. Learn more.

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 5, 2026
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

CI: add governance-enforce A_BLOCK diff-scoped gate

⚙️ Configuration changes ✨ Enhancement 🕐 10-20 Minutes

Grey Divider

AI Description

• Add a required enforce CI check to block new secrets and hardcoded paths.
• Run enforcement diff-scoped on PRs and on pushes to main/master.
• Install @wave-av/governance in isolation with least-privilege GitHub Packages access.
Diagram

graph TD
  A{{"PR / push"}} --> B["Workflow: governance-enforce"] --> C["Job: enforce"] --> D["Install @wave-av/governance"] --> E["Run enforce.mjs on diff"] --> F["Status check: enforce"]
  D --> G[("GitHub Packages")]
  subgraph Legend
    direction LR
    _evt{{"Trigger"}} ~~~ _job["Job/Step"] ~~~ _reg[("Registry")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Public reusable workflow for governance-enforce
  • ➕ Single source of truth across repos; updates roll out without vendoring.
  • ➕ Avoids per-repo drift and keeps policy logic consistent.
  • ➖ Requires a public repo/visibility strategy and governance of who can change it.
  • ➖ Still needs careful rollout to avoid required-check deadlocks.
2. Rely on GitHub Advanced Security secret scanning/push protection
  • ➕ Native platform capability; minimal custom maintenance.
  • ➕ Works well for common secret patterns.
  • ➖ May not cover org-specific rules like Doppler sourcing or hardcoded-path policies.
  • ➖ Does not naturally provide diff-scoped 'new violations only' behavior for all checks.

Recommendation: The vendored workflow is the right rollout mechanism here because it guarantees the enforce check exists (and can be observed green) before the repo is added to a required-check ruleset, avoiding a permanent merge deadlock. If this is expected to propagate broadly, consider moving to a public reusable workflow later to reduce long-term maintenance and drift, while preserving the same check name and permissions model.

Files changed (1) +59 / -0

Other (1) +59 / -0
governance-enforce.ymlAdd diff-scoped A_BLOCK governance enforcement workflow +59/-0

Add diff-scoped A_BLOCK governance enforcement workflow

• Introduces a new GitHub Actions workflow that runs on pull requests and on pushes to main/master to enforce A_BLOCK policies (secrets and hardcoded paths) on the changed diff. The job installs @wave-av/governance from GitHub Packages using the repo GITHUB_TOKEN and runs the enforcer against a computed base SHA while keeping least-privilege permissions and SHA-pinned actions.

.github/workflows/governance-enforce.yml

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment on lines +44 to +48
- name: fetch governance enforcer (isolated install)
run: |
mkdir -p "$RUNNER_TEMP/gov" && cd "$RUNNER_TEMP/gov"
printf '@wave-av:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' > .npmrc
npm install @wave-av/governance@^0.4.4 --no-save --no-audit --no-fund

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Fork PRs will run this gate but may not be able to read the private org package

This repo is PUBLIC (see the rationale comments in .github/workflows/foundation-gate.yml:1-10 and .github/workflows/public-repo-guard.yml), so pull_request runs from forks are expected. Those runs get a read-only GITHUB_TOKEN scoped to the base repo; if @wave-av/governance on npm.pkg.github.com is not granted org/internal read visibility, the isolated npm install at line 48 returns 401 and the enforce job fails for every external contributor's PR — indistinguishable from a real A_BLOCK violation. The header comment cites wave-av/cli#20 as proof, but a same-repo branch PR does not exercise the fork token path. Worth verifying with one fork PR before this check is added to governance-a-block-enforce.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread .github/workflows/governance-enforce.yml Outdated
@qodo-code-review

qodo-code-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Caret-pinned enforcer version ✓ Resolved 🐞 Bug ☼ Reliability
Description
The workflow installs @wave-av/governance with @^0.4.4, so the required enforce check can
change behavior between runs without any PR in this repo. That can introduce unexpected failures or
rule drift in a branch-protection gate.
Code

.github/workflows/governance-enforce.yml[R47-48]

+          printf '@wave-av:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' > .npmrc
+          npm install @wave-av/governance@^0.4.4 --no-save --no-audit --no-fund
Evidence
The new workflow installs the enforcer via a caret range, allowing version drift across runs. In
contrast, the existing public-repo guard workflow explicitly documents and implements pinned,
deterministic scanning behavior (version pinning + checksum verification), showing that this repo
treats scanners/gates as needing reproducibility.

.github/workflows/governance-enforce.yml[44-48]
.github/workflows/public-repo-guard.yml[9-15]
.github/workflows/public-repo-guard.yml[47-60]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow installs `@wave-av/governance` using a caret range (`^0.4.4`). This makes the `enforce` required check non-deterministic (npm can resolve newer compatible versions), which can change gating behavior without review in this repo.

### Issue Context
This repo already has a security gate workflow that emphasizes determinism and pinning for scanners.

### Fix Focus Areas
- .github/workflows/governance-enforce.yml[44-48]

### Suggested fix
- Replace `npm install @wave-av/governance@^0.4.4 ...` with an exact version (e.g., `@0.4.4`).
- Establish an intentional update mechanism (scheduled/PR-based bump) so rule changes remain reviewable in this repo.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. HEAD fallback skips scan ✓ Resolved 🐞 Bug ≡ Correctness
Description
If neither PR_BASE_SHA nor PUSH_BEFORE_SHA is available (or before is all-zero), the script
can fall back to BASE=HEAD, which makes the --changed "$BASE" comparison empty and can let new
violations slip through unscanned in parentless/root-commit edge cases. This is a fail-open behavior
for a security gate.
Code

.github/workflows/governance-enforce.yml[R55-57]

+          if [ -z "$BASE" ] || [ "$BASE" = "0000000000000000000000000000000000000000" ]; then
+            BASE=$(git rev-parse HEAD~1 2>/dev/null || git rev-parse HEAD)
+          fi
Evidence
The workflow explicitly sets BASE from event SHAs, then falls back to HEAD~1 or HEAD, and
immediately runs the enforcer using --changed "$BASE". If BASE becomes HEAD, the resulting
comparison is against the current revision and can produce an empty change set, which is a fail-open
outcome for enforcement; other repo gates are documented/implemented as fail-closed.

.github/workflows/governance-enforce.yml[50-59]
.github/workflows/_checks.yml[26-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
When the workflow cannot determine a valid base SHA, it falls back to `git rev-parse HEAD`, which can result in `BASE==HEAD`. Passing `--changed HEAD` makes the diff empty and can silently skip scanning the introduced changes.

### Issue Context
This is an edge case (e.g., root commit, unusual checkout state), but it turns a missing-base condition into a pass rather than an error or a full-tree scan.

### Fix Focus Areas
- .github/workflows/governance-enforce.yml[54-59]

### Suggested fix
Pick one fail-safe strategy:
1) **Fail closed**: if no valid base can be computed, `echo ::error::...` and `exit 1`.
2) **Root-commit safe diff**: if `HEAD~1` is unavailable, set `BASE` to the empty-tree hash (`4b825dc642cb6eb9a060e54bf8d69288fbee4904`) so the scan covers all files in the commit.

Either approach prevents an empty-diff bypass for this required gate.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context used
✅ Compliance rules (platform): 2 rules
Review mode: ⚖️ Balanced: This adds a security-sensitive CI governance gate with workflow, package-install, token, permissions, and diff-base behavior that warrants a careful single-pass review.

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

qodo-code-review[bot]

This comment was marked as resolved.

@qodo-code-review

Copy link
Copy Markdown

Qodo Fixer

No findings are within the configured fix scope. To change which findings are fixed, adjust the setting on your Qodo configuration page.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 1 file

Confidence score: 3/5

  • In .github/workflows/governance-enforce.yml, using a caret-pinned governance package with default npm lifecycle execution makes the security gate non-deterministic, so a future upstream release could silently change enforcement behavior and create unexpected pass/fail outcomes — pin an exact immutable version (and consider lockfile/npm ci style installs) to stabilize checks.
  • In .github/workflows/governance-enforce.yml, pull_request runs from forks may not be able to read @wave-av/governance from npm.pkg.github.com with the default read-only GITHUB_TOKEN, which can cause governance checks to fail for external contributors and block PR flow — add a fork-safe auth strategy or a fallback path for forked PRs.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/governance-enforce.yml">

<violation number="1" location=".github/workflows/governance-enforce.yml:48">
P2: The security gate is not deterministic: the caret range and default npm lifecycle execution allow a later package release or dependency to alter enforcement without a workflow change. Pin an immutable package version with dependency integrity and install with lifecycle scripts disabled where the enforcer does not require them.</violation>

<violation number="2" location=".github/workflows/governance-enforce.yml:48">
P2: This is a public repo, so `pull_request` runs from forks are expected, and fork runs get a read-only `GITHUB_TOKEN` scoped to the base repo. If `@wave-av/governance` on `npm.pkg.github.com` isn't readable with that token for external contributors, this install step will 401 and fail the required `enforce` check for every fork PR, indistinguishable from a real A_BLOCK violation. Worth verifying with an actual fork PR before adding this check to the `governance-a-block-enforce` required-check ruleset.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant GH as GitHub Actions
    participant Runner as CI Runner (Transient)
    participant Registry as GitHub Packages (@wave-av)
    participant Git as Git History
    participant Status as PR Status Checks

    Note over GH,Status: NEW: governance-enforce Workflow

    GH->>Runner: pull_request event
    Runner->>Git: checkout (fetch-depth: 0)
    
    Note over Runner,Registry: Isolated Tooling Installation
    Runner->>Runner: NEW: Write .npmrc to RUNNER_TEMP
    Note right of Runner: Uses ephemeral GITHUB_TOKEN<br/>for internal package access
    
    Runner->>Registry: NEW: npm install @wave-av/governance
    Registry-->>Runner: Return enforcer package
    
    Note over Runner,Git: Diff-Scoped Detection
    alt pull_request
        Runner->>Runner: Identify PR_BASE_SHA
    else push
        Runner->>Runner: Identify PUSH_BEFORE_SHA
    end

    Runner->>Git: git diff [BASE]...HEAD
    Runner->>Runner: NEW: Exec enforce.mjs (bin)
    
    alt Secrets or Hardcoded Paths Found in Diff
        Runner-->>Status: NEW: Report 'enforce' check FAILURE
        Note over Status: Blocks Merge (once added to Ruleset)
    else No New Violations
        Runner-->>Status: NEW: Report 'enforce' check SUCCESS
        Note over Status: Liveness Drill: Verifies repo can run check
    end
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .github/workflows/governance-enforce.yml Outdated
Comment thread .github/workflows/governance-enforce.yml Outdated
run: |
mkdir -p "$RUNNER_TEMP/gov" && cd "$RUNNER_TEMP/gov"
printf '@wave-av:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' > .npmrc
npm install @wave-av/governance@^0.4.4 --no-save --no-audit --no-fund

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The security gate is not deterministic: the caret range and default npm lifecycle execution allow a later package release or dependency to alter enforcement without a workflow change. Pin an immutable package version with dependency integrity and install with lifecycle scripts disabled where the enforcer does not require them.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/governance-enforce.yml, line 48:

<comment>The security gate is not deterministic: the caret range and default npm lifecycle execution allow a later package release or dependency to alter enforcement without a workflow change. Pin an immutable package version with dependency integrity and install with lifecycle scripts disabled where the enforcer does not require them.</comment>

<file context>
@@ -0,0 +1,59 @@
+        run: |
+          mkdir -p "$RUNNER_TEMP/gov" && cd "$RUNNER_TEMP/gov"
+          printf '@wave-av:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' > .npmrc
+          npm install @wave-av/governance@^0.4.4 --no-save --no-audit --no-fund
+      - name: A_BLOCK enforce (secrets + hardcoded paths on the diff)
+        env:
</file context>

run: |
mkdir -p "$RUNNER_TEMP/gov" && cd "$RUNNER_TEMP/gov"
printf '@wave-av:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' > .npmrc
npm install @wave-av/governance@^0.4.4 --no-save --no-audit --no-fund

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This is a public repo, so pull_request runs from forks are expected, and fork runs get a read-only GITHUB_TOKEN scoped to the base repo. If @wave-av/governance on npm.pkg.github.com isn't readable with that token for external contributors, this install step will 401 and fail the required enforce check for every fork PR, indistinguishable from a real A_BLOCK violation. Worth verifying with an actual fork PR before adding this check to the governance-a-block-enforce required-check ruleset.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/governance-enforce.yml, line 48:

<comment>This is a public repo, so `pull_request` runs from forks are expected, and fork runs get a read-only `GITHUB_TOKEN` scoped to the base repo. If `@wave-av/governance` on `npm.pkg.github.com` isn't readable with that token for external contributors, this install step will 401 and fail the required `enforce` check for every fork PR, indistinguishable from a real A_BLOCK violation. Worth verifying with an actual fork PR before adding this check to the `governance-a-block-enforce` required-check ruleset.</comment>

<file context>
@@ -0,0 +1,59 @@
+        run: |
+          mkdir -p "$RUNNER_TEMP/gov" && cd "$RUNNER_TEMP/gov"
+          printf '@wave-av:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' > .npmrc
+          npm install @wave-av/governance@^0.4.4 --no-save --no-audit --no-fund
+      - name: A_BLOCK enforce (secrets + hardcoded paths on the diff)
+        env:
</file context>

…othing

Five defects, none of them cosmetic. Refs wave-av/claude-workstation#1747.

1. FAIL-OPEN DIFF BASE. `BASE=$(git rev-parse HEAD~1 2>/dev/null || git rev-parse HEAD)`
   — on a root commit `git rev-parse HEAD~1` prints its unresolved argument to stdout AND
   fails, so the `||` branch appends and BASE becomes a two-line string. `git diff` then
   exits 128, and the pinned enforcer turned that into zero files and a green check. Now:
   a reachability-checked base (a force-push can leave `github.event.before` pointing at a
   commit this checkout does not have), and with no resolvable base at all it diffs against
   the EMPTY TREE so the whole repo is scanned rather than nothing.

2. THE PINNED ENFORCER ITSELF FAILED OPEN. `^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 A_BLOCK violations`. A git error and a clean
   diff were byte-identical in the output. The fix had sat unreleased on claude-workstation
   main since 2026-07-29 because no `governance-v*` tag was ever pushed. Released now as
   0.4.6 and pinned exactly here.

3. TOKEN IN SCOPE FOR THE WRONG STEPS. `NODE_AUTH_TOKEN` was job-level, so it was also in
   the environment of the step that executes the downloaded package. Now step-scoped, and
   the .npmrc holding it is removed on exit.

4. INSTALL SCRIPTS RAN WITH THAT TOKEN. `npm install` runs preinstall/postinstall by
   default. Added `--ignore-scripts`.

5. CANCELLED PUSH RUNS WERE SCANNED BY NOBODY. `cancel-in-progress: true` applied to push
   runs, and each push run only diffs its own before..HEAD range — so a cancelled run's
   commits were never examined by anything. Now PR-only.

Also: `timeout-minutes: 10` and `set -euo pipefail`.

Receipt, against a scratch repo whose root commit carries a no-hardcoded-paths violation,
simulating a branch-creation push (`before` = all zeros):
  old logic -> malformed base -> caught error -> [] -> OK, 0 files scanned, PASS
  new logic -> "no diff base resolved ... scanning the whole tree" -> BLOCK, exit 1

Credit where it is due: several of these were found by the review bots on the sibling
vendoring PRs and are folded in here — the step-scoped token, the .npmrc cleanup, the exact
pin, `--ignore-scripts`, the force-push reachability check, `timeout-minutes`, and the
concurrency hole (5), which was crest-console#7's catch and which I had missed entirely.
@cursor

cursor Bot commented Aug 6, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_154d443d-c097-4e68-8855-4535810380a8)

# pointing at a commit this checkout no longer contains.
if [ -z "$BASE" ] || [ "$BASE" = "0000000000000000000000000000000000000000" ] \
|| ! git cat-file -e "$BASE^{commit}" 2>/dev/null; then
BASE="$(git rev-parse --verify --quiet 'HEAD~1' || true)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High workflows/governance-enforce.yml:80

When a force-push makes github.event.before unreachable, the fallback selects HEAD~1 and the gate scans only the newest commit. A force-push that introduces multiple commits can hide secrets in the earlier commits — they never appear in the HEAD~1..HEAD diff, so the gate reports green without examining them. This contradicts the workflow's stated goal of failing closed on unverified input. Consider falling back to the empty tree (as the no-base branch already does) instead of HEAD~1, so the entire force-pushed history is scanned.

-            BASE="$(git rev-parse --verify --quiet 'HEAD~1' || true)"
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.github/workflows/governance-enforce.yml around line 80:

When a force-push makes `github.event.before` unreachable, the fallback selects `HEAD~1` and the gate scans only the newest commit. A force-push that introduces multiple commits can hide secrets in the earlier commits — they never appear in the `HEAD~1..HEAD` diff, so the gate reports green without examining them. This contradicts the workflow's stated goal of failing closed on unverified input. Consider falling back to the empty tree (as the no-base branch already does) instead of `HEAD~1`, so the entire force-pushed history is scanned.

Evidence trail:
.github/workflows/governance-enforce.yml:74-93 @ 31eeb1c7

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

Open in Devin Review

Comment thread .github/workflows/governance-enforce.yml Outdated
Comment on lines +88 to +93
if [ -z "$BASE" ]; then
BASE="$(git hash-object -t tree /dev/null)"
echo "::notice::no diff base resolved (root commit or unreachable before-sha) — scanning the whole tree against the empty tree"
fi
echo "diffing against $BASE"
exec node "$ENFORCE" --changed "$BASE"

@devin-ai-integration devin-ai-integration Bot Aug 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Empty-tree SHA as --changed argument may not be accepted by the enforcer

The fail-closed path passes the empty tree object id to node enforce.mjs --changed "$BASE". This only works if the enforcer diffs with a two-dot form (git diff <base> HEAD) or git diff --name-only <base>. If it uses the three-dot form (git diff base...HEAD), git needs a merge base and will error out on a tree object, so the whole-tree fallback would abort rather than scan. The package is not vendored here, so this could not be verified from the repo. Worth confirming against @wave-av/governance@0.4.6 behaviour (ideally by exercising the root-commit/unreachable-base path once).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified against the enforcer source: --changed uses the two-argument form git diff <base> HEAD (changedArgs() in governance/lib/git-files.mjs), explicitly documented to accept tree objects like the empty tree, and its file lister fails closed (non-zero exit) on any git error rather than reporting a pass.

…AD~1

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment on lines +86 to +90
if [ -z "$BASE" ] || [ "$BASE" = "0000000000000000000000000000000000000000" ] \
|| ! git cat-file -e "$BASE^{commit}" 2>/dev/null; then
BASE="$(git hash-object -t tree /dev/null)"
echo "::notice::no verifiable diff base (root commit, branch creation, or force-push with unreachable before-sha) — scanning the whole tree against the empty tree"
fi

Copy link
Copy Markdown

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 gate into a whole-repo scan that can fail on legacy debt

The fail-closed path replaces an unverifiable base with the empty-tree hash, so every tracked file reads as added and the enforcer scans the entire repository. That contradicts the header claim that this gate is "diff-scoped: blocks NEW violations without failing on legacy debt" — on a force-push (or any push whose before sha is unreachable), the run will report every pre-existing A_BLOCK violation in the repo, potentially wedging pushes to main until legacy debt is cleaned or a suppression list exists. The trade-off is deliberate per the comment, but it's worth confirming this repo currently scans clean against the empty tree before the check is made required (which the header also warns about).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trade-off is deliberate and documented at the fallback site; I ran the requested verification and this repo scans clean against the empty tree (enforce.mjs exit 0, 0 A_BLOCK violations across all 34 tracked files), so the whole-repo fallback cannot block on legacy debt.

…l a false pass

Correction to the previous commit on this branch. Refs wave-av/claude-workstation#1747.

That commit replaced the fail-open `BASE=HEAD` with a fallback to `HEAD~1`. `HEAD~1` is
also wrong: it scans exactly ONE commit, so a five-commit push whose base is indeterminate
(branch creation, force-push, unreachable `github.event.before`) examines the last commit
and reports a confident pass on the other four. A narrowed scan reported as a full pass is
the same defect in a quieter costume.

Receipt — scratch repo, five-commit push, violation planted in commit 1:
  HEAD~1 base      -> OK[enforce]: 1 changed file(s) scanned  -> PASS   (never saw it)
  empty-tree base  -> 5 changed file(s) scanned -> BLOCK[enforce]: no-hardcoded-paths, exit 1

Now: with no resolvable base of any kind, diff against git's empty-tree object so every
tracked file reads as added and the whole repo is scanned. Loud, never partial, never empty.

Credit: wave-av/wave-rig's copy on main already had this right, with the reasoning in a
comment ("HEAD~1 would skip earlier commits in a multi-commit push and let a violation
through"). The fan-out copied the broken shape from elsewhere and I did not check the one
repo that had already solved it.

Also from wave-rig: `merge_group` is now a declared trigger and `github.event.merge_group.
base_sha` joins the base chain. None of these repos runs a merge queue today, so the trigger
is inert — but a required check that never reports on an event the repo actually uses is a
permanent deadlock, and this closes that in advance rather than after someone hits it.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment on lines +73 to +79
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:-}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 pull_request base.sha vs merge-commit checkout can widen the scanned range

For pull_request, github.event.pull_request.base.sha is the base tip at event time while the checkout is refs/pull/N/merge, which merges in the current base tip. If the enforcer uses a two-dot diff, commits landed on the base branch after the event are attributed to this PR and can fail it on someone else's changes; a three-dot diff avoids this. Passing the merge base (or relying on the enforcer's three-dot semantics) is worth confirming.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rr:skip-cubic RF.P1 reviewer routing (#1039)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant