Skip to content

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

Merged
yakimoto merged 7 commits into
mainfrom
ci/vendor-governance-enforce
Sep 6, 2026
Merged

ci: vendor governance-enforce — this repo was never in the A_BLOCK ruleset#41
yakimoto merged 7 commits into
mainfrom
ci/vendor-governance-enforce

Conversation

@yakimoto

@yakimoto yakimoto commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

User description

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.


Note

Medium Risk
Adds a required-style security CI gate that can block merges on new secret/path violations; misconfiguration of diff base handling is mitigated by fail-closed full-tree fallback.

Overview
Introduces .github/workflows/governance-enforce.yml, an org A_BLOCK gate that runs @wave-av/governance@0.4.6 on pull requests, merge groups, and pushes to main/master. It scans only changed files (secrets-in-git, Doppler expectations, hardcoded paths) so new violations fail without reopening legacy debt.

The workflow is a hardened vendored copy: SHA-pinned actions, read-only permissions, isolated GitHub Packages install with --ignore-scripts, registry token limited to the install step, and exact enforcer pin (avoids silent “0 files scanned” passes). Concurrency cancels superseded PR runs but not push runs, so no push commit range is skipped. If the diff base is missing or unreachable (new branch, bad before SHA), it fails closed by diffing against the empty tree and scanning the full repo instead of passing on an empty diff.

This lands before adding the repo to the org governance-a-block-enforce ruleset so the required enforce check exists and can go green first.

Reviewed by Cursor Bugbot for commit 7d01cf5. Bugbot is set up for automated code reviews on this repo. Configure here.


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

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 7d01cf5.

Summary by Sourcery

Add and harden repository-level governance enforcement to scan changes for security policy violations without blocking on legacy debt.

New Features:

  • Add a governance enforcement workflow that scans pull request, merge-group, and main/master push changes for secrets and hardcoded paths.

Bug Fixes:

  • Ensure indeterminate or unreachable diff bases trigger a full-tree scan instead of silently passing with an empty or partial scan.
  • Prevent push scans from being cancelled so committed changes are not left unchecked.

Enhancements:

  • Harden the isolated governance package installation with read-only permissions, pinned dependencies, disabled install scripts, and scoped credentials.

CI:

  • Vendor the diff-scoped A_BLOCK enforcement check into the repository before enabling it as a required status check.

CodeAnt-AI Description

Add a fail-closed governance scan for changed files

What Changed

  • Pull requests, merge queues, and pushes to the main branches now scan changed files for secrets and hardcoded paths.
  • If the change base is missing or unreachable, the workflow scans the entire repository instead of silently scanning nothing.
  • Git or scan errors now fail the check rather than producing a passing result with zero files examined.
  • The scanner is pinned to a known version, has a 10-minute limit, and limits the package registry token to installation only.

Impact

✅ Fewer unscanned security changes
✅ No false passes from empty or partial diffs
✅ Reduced exposure of registry credentials

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@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_3c6fae05-d067-4873-b826-e38fdb981d50)

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 58 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 91 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

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

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: 86899956-3823-4c5c-87c8-b2994f2647bf

📥 Commits

Reviewing files that changed from the base of the PR and between 756588b and 7d01cf5.

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

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

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 5, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 5, 2026

Copy link
Copy Markdown

Approvability

Verdict: Needs human review

Unable to check for correctness in dfb2d1f. Adds a new governance enforcement CI workflow with security scanning. An unresolved review comment questions whether the empty-tree fallback mechanism will work correctly with the enforcer's diff implementation, raising a substantive technical concern that should be addressed.

No code changes detected at 7d01cf5. Prior analysis still applies.

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

devin-ai-integration[bot]

This comment was marked as resolved.

…install step

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

Copy link
Copy Markdown

PR Summary by Qodo

Add diff-scoped governance-enforce A_BLOCK gate to CI

✨ Enhancement ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

AI Description

• Add a GitHub Actions workflow that runs A_BLOCK governance checks on PR diffs.
• Fetch @wave-av/governance from GitHub Packages with least-privilege, isolated install.
• Fail closed when no diff base commit is available to prevent unscanned passes.
Diagram

graph TD
  A["GitHub event (PR/Push)"] --> B["Checkout repo"] --> C["Setup Node 22"] --> D["Isolated npm install @wave-av/governance"] --> E["Compute diff base SHA"] --> F["Run enforce on changed files"]
  D --> G["GitHub Packages (npm)"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Reusable workflow from a central repo
  • ➕ Single source of truth; easier fleet-wide updates
  • ➕ Reduces duplication across repos
  • ➖ Public repos can’t safely depend on private reusable workflows; parse-time failures can silently skip jobs
  • ➖ Cross-repo coupling increases blast radius if the central workflow changes unexpectedly
2. Use GitHub Advanced Security secret scanning / CodeQL gates
  • ➕ Native platform support, less custom code to maintain
  • ➕ No need to fetch internal npm packages at workflow runtime
  • ➖ May not replicate the same A_BLOCK rule set (e.g., hardcoded-path policy) or diff-scoped behavior
  • ➖ Enterprise feature availability/consistency may vary across repos and doesn’t enforce the same org-defined contract check name
3. Publish a dedicated GitHub Action for the enforcer
  • ➕ Avoids runtime npm install complexity and token handling per workflow
  • ➕ Versioning via action tags/SHAs can be simpler than npm auth setup
  • ➖ Requires building and maintaining an action distribution pipeline
  • ➖ Still needs access control to private logic and careful pinning/upgrades

Recommendation: The PR’s approach (vendored workflow + isolated install of @wave-av/governance with scoped token and SHA-pinned actions) is the most reliable for a public repo while preserving the org-required enforce check name and diff-scoped scanning. A central reusable workflow would be attractive, but cross-repo reuse is brittle for public repos; a dedicated action could be a future simplification once distribution and access constraints are solved.

Files changed (1) +64 / -0

Other (1) +64 / -0
governance-enforce.ymlAdd governance-enforce A_BLOCK diff-scoped CI gate +64/-0

Add governance-enforce A_BLOCK diff-scoped CI gate

• Introduces a new GitHub Actions workflow that runs an 'enforce' job on PRs and pushes to main/master. The job installs @wave-av/governance in an isolated temp directory using GITHUB_TOKEN for GitHub Packages access, computes a safe diff base SHA (and fails closed if unavailable), then runs the enforcer against changed files only.

.github/workflows/governance-enforce.yml

@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. No job timeout ✓ Resolved 🐞 Bug ☼ Reliability
Description
The new required enforce job has no timeout-minutes, so in worst cases (e.g., stuck npm/network
operations) the check can run until the platform default timeout, consuming runners and delaying
merges. Adding an explicit timeout bounds impact even though concurrency cancellation reduces
repeated-run accumulation.
Code

.github/workflows/governance-enforce.yml[R31-34]

+jobs:
+  enforce:
+    runs-on: ubuntu-latest
+    steps:
Evidence
The new enforce job definition lacks a timeout-minutes field, while other gating jobs in this
repo explicitly set timeouts (demonstrating an existing reliability practice for CI gates).

.github/workflows/governance-enforce.yml[31-36]
.github/workflows/_checks.yml[18-23]

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 `enforce` job does not set `timeout-minutes`, so a hung/stalled run can occupy CI resources and keep the required check pending for an extended period.

### Issue Context
Other gate-style jobs in this repo explicitly bound runtime with `timeout-minutes`.

### Fix
- Add `timeout-minutes` to `jobs.enforce` (e.g., 10–15 minutes, tuned to typical install + scan duration).

### Fix Focus Areas
- .github/workflows/governance-enforce.yml[31-40]
- .github/workflows/_checks.yml[18-23]

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


2. Unpinned enforcer version ✓ Resolved 🐞 Bug ⛨ Security
Description
The workflow installs @wave-av/governance with a caret range (^0.4.4), so the required
enforcement check can change behavior or break due to a newly published compatible release without
any PR in this repo. This makes the gate non-deterministic and can unexpectedly block merges or
change enforcement semantics out-of-band.
Code

.github/workflows/governance-enforce.yml[R46-49]

+          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
+          rm -f .npmrc
Evidence
The workflow installs the governance enforcer with @^0.4.4, which allows different resolved
versions over time. The repo’s existing secret/content gate documents and implements pinned,
deterministic tooling (including checksum verification), showing an established expectation for
reproducible security gates.

.github/workflows/governance-enforce.yml[42-49]
.github/workflows/public-repo-guard.yml[9-15]
.github/workflows/public-repo-guard.yml[47-55]

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 semver range (`^0.4.4`), making this required check non-deterministic across time.

### Issue Context
This job is intended to be a required A_BLOCK enforcement gate; other security gates in this repo emphasize deterministic, pinned tooling.

### Fix
- Change the install to an exact version (e.g. `@wave-av/governance@0.4.4`) or to a repo-managed pinned variable.
- (Optional) Add additional hardening (e.g., lockfile-based install in the temp dir, or other integrity controls appropriate for your environment).

### Fix Focus Areas
- .github/workflows/governance-enforce.yml[42-49]

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


Grey Divider

Context used
✅ Compliance rules (platform): 1 rule
Review mode: ⚖️ Balanced: This adds a security-sensitive CI governance gate with package installation, token permissions, diff-base logic, and required-check liveness implications; one localized workflow still 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.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

… exit paths

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
cubic-dev-ai[bot]

This comment was marked as resolved.

…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_bac84256-0d28-4d0b-b38c-72896fa74541)

@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 thread .github/workflows/governance-enforce.yml Outdated
…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 thread .github/workflows/governance-enforce.yml
@codeant-ai

codeant-ai Bot commented Sep 6, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR 7d01cf5 Sep 06, 2026 · 03:24 03:26

@codeant-ai

codeant-ai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@cursor

cursor Bot commented Sep 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_618306f2-5c05-4662-95d9-479bcbe0e6e7)

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Sep 6, 2026
@codeant-ai

codeant-ai Bot commented Sep 6, 2026

Copy link
Copy Markdown

CodeAnt Nitpicks

1 code suggestion

1. Unusable event bases trigger a full-tree scan, so legacy violations can fail branch creation or force-pushed PRs despite the workflow's diff-scoped contract.

Api mismatch · .github/workflows/governance-enforce.yml:101-105

@yakimoto

yakimoto commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Re devin-ai thread on the empty-tree fallback (line 88-91): even in the worst case where the enforcer's diff path rejects the empty-tree object ("not a commit"), the job fails loudly rather than silently passing — that is the exact invariant FIX 5 documents ("loud, never partial, never empty"). A hard-fail here is a correct outcome for an indeterminate base, not a defect; it is not a case where the gate returns a false PASS. Not changing the fallback base; resolving.

Re devin-ai thread on checkout SHA pins diverging from foundation-gate.yml (v6.0.3 here vs v4.3.1 there): intentional — this workflow is copied verbatim from the already-green pilot (wave-av/cli#20 / wave-moq-edge), per this PR's description, and each workflow's action pins are independently bumped on their own schedule (Dependabot/Renovate). No correctness coupling between the two files' pins. Resolving as by-design.

@yakimoto
yakimoto merged commit e6ce0a0 into main Sep 6, 2026
23 of 24 checks passed
@yakimoto
yakimoto deleted the ci/vendor-governance-enforce branch September 6, 2026 05:04
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) size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant