Skip to content

fix(ci): governance-enforce gate can pass having scanned nothing - #39

Open
yakimoto wants to merge 3 commits into
mainfrom
fix/1747-enforce-diff-base-fail-open
Open

fix(ci): governance-enforce gate can pass having scanned nothing#39
yakimoto wants to merge 3 commits into
mainfrom
fix/1747-enforce-diff-base-fail-open

Conversation

@yakimoto

@yakimoto yakimoto commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Defect

.github/workflows/governance-enforce.yml resolved its diff base to HEAD~1, which scans only
ONE commit of a multi-commit push and reports every earlier commit as passing. On an initial push,
force-push, or shallow clone this degrades further: HEAD~1 fails to resolve and falls back to
BASE=HEAD, diffing HEAD against itself — an empty diff, zero lines scanned, job green. A gate
that passes without reading any line is worse than no gate.

Changes (targeted, .github/workflows/governance-enforce.yml only)

  1. Add a merge_group: trigger alongside pull_request: / push: — also clears a latent
    merge-queue deadlock (the gate previously never ran in the merge queue).
  2. Add MERGE_BASE_SHA: ${{ github.event.merge_group.base_sha }} to the env of the step that
    computes BASE.
  3. Replace the base resolution: BASE="${PR_BASE_SHA:-$PUSH_BEFORE_SHA}" becomes
    BASE="${PR_BASE_SHA:-${MERGE_BASE_SHA:-$PUSH_BEFORE_SHA}}", and the indeterminate-base
    fallback (previously git rev-parse HEAD~1 2>/dev/null || git rev-parse HEAD) now diffs against
    git's empty-tree object (git hash-object -t tree /dev/null) so the full tree is scanned —
    loud (::warning::) and never a silent empty/partial pass.

wave-av/wave-conferencing-bridge, wave-monitor, wave-desktop, and wave-multiviewer already
carry the correct form of this file; this brings the same fix to this repo.

Out of scope (tracked separately, claude-workstation#1747)

This repo's gate still has three OTHER open defects tracked in #1747 which are deliberately NOT
addressed here: fail-open token scope, unpinned install scripts, and a caret (^) version range
on the @wave-av/governance dependency.

Refs claude-workstation#1747.


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


Open in Devin Review

Note

Cursor Bugbot is generating a summary for commit b1958cf. Configure here.

Review in cubic

Note

Fix governance-enforce gate to scan full tree when diff base is unresolvable

  • Adds merge_group as a workflow trigger in governance-enforce.yml so the gate runs on merge queue events.
  • Improves base SHA resolution to prefer PR_BASE_SHA, then MERGE_BASE_SHA, then PUSH_BEFORE_SHA.
  • When the resolved base is missing or not a valid commit, computes the empty-tree hash via git hash-object -t tree /dev/null and scans the full tree, emitting a GitHub Actions warning instead of silently passing or diffing against HEAD~1.
  • Bumps the @wave-av/governance install floor from ^0.4.4 to ^0.4.6.

Macroscope summarized defc1a5.

…ead nothing

BASE=HEAD~1 scans one commit of a multi-commit push and reports the rest as
passing; when HEAD~1 does not resolve it degrades to BASE=HEAD, an empty diff
and a green job. Resolve to the empty-tree object so the full tree is scanned,
and add merge_group so the gate runs in the merge queue. Refs #1747.
@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_4ef0317e-262d-4b3d-a735-f56f58faa358)

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fix governance-enforce diff base resolution to prevent empty/partial scans

🐞 Bug fix ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

AI Description

• Run governance-enforce in merge queue via merge_group trigger.
• Resolve diff base from PR/merge-group/push metadata instead of HEAD~1.
• On indeterminate base, scan full tree via empty-tree base with a warning.
Diagram

graph TD
  A["GitHub event"] --> B["governance-enforce job"] --> C["Resolve BASE sha"] --> D{BASE known?} --> E["enforce --changed BASE"]
  D -->|"no"| F["Use empty-tree BASE"] --> E
  D -->|"yes"| E
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Compute merge-base against default branch (git merge-base)
  • ➕ Works even when event payload SHAs are missing/zeroed
  • ➕ Naturally handles multi-commit pushes by finding the true fork point
  • ➖ Requires reliable access to the default branch ref and usually fetch-depth=0
  • ➖ More git/network work; slightly slower and more failure modes (fetch/auth)
2. Force full history checkout (fetch-depth: 0) and keep HEAD~1 fallback
  • ➕ Simple mental model; makes HEAD~1 usually resolvable
  • ➖ Still incorrect for multi-commit pushes (HEAD~1 scans only one commit)
  • ➖ Does not address first push / force-push cases where before SHA is zero and range semantics are ambiguous

Recommendation: Current approach is the best fit for a targeted fix: prefer explicit event-provided bases (PR base, merge-queue base, push before SHA), and when that’s indeterminate, intentionally scan the full tree via the empty-tree base and emit a warning. This eliminates the dangerous silent pass condition without adding extra network fetch complexity.

Files changed (1) +9 / -2

Bug fix (1) +9 / -2
governance-enforce.ymlPrevent governance gate from passing with empty/partial diffs +9/-2

Prevent governance gate from passing with empty/partial diffs

• Adds merge_group triggering so the gate runs in merge queues. Updates diff base selection to prefer PR base, then merge-queue base, then push-before SHA. Replaces the HEAD~1/HEAD fallback with an empty-tree base (and a warning) to ensure a full-tree scan when the base is indeterminate.

.github/workflows/governance-enforce.yml

devin-ai-integration[bot]

This comment was marked as resolved.

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

macroscopeapp Bot commented Aug 6, 2026

Copy link
Copy Markdown

Approvability

Verdict: Approved defc1a5

CI workflow fix to governance enforcement gate, owned by the PR author. Review comments note the intentional design choice (fail loud vs silent pass) and one suggests a guard already present in the code. Low-risk configuration change.

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

@coderabbitai

coderabbitai Bot commented Aug 6, 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: 46 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1d8b87a8-ac78-4c2e-ba94-c52f5c6597b2

📥 Commits

Reviewing files that changed from the base of the PR and between d9be379 and defc1a5.

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

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

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

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

Qodo Logo

@qodo-code-review

Copy link
Copy Markdown

Qodo Fixer

No findings are available for this PR yet. Findings appear here once Qodo has reviewed the PR.

…nnot silently pass

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 6, 2026

@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 on lines +52 to +57
# Indeterminate base (first push / force-push). Do NOT silently scan a partial range —
# HEAD~1 would skip earlier commits in a multi-commit push and let a violation through
# (a config-no-silent-noop hole). Diff the full tree against git's empty-tree object so
# every introduced file is scanned; loud, never a silent empty/partial pass.
BASE=$(git hash-object -t tree /dev/null)
echo "::warning::indeterminate diff base; scanning full tree (empty-tree base) so no commit is skipped"

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

🟡 First push of a new branch makes the compliance check scan the whole repository and fail on old, pre-existing problems

When the check cannot determine what to compare against, it now compares the entire repository against nothing (git hash-object -t tree /dev/null at .github/workflows/governance-enforce.yml:56) instead of a recent change range, so every historical file is treated as newly added.
Impact: On a branch's first push (or branch creation), the gate can fail on long-standing legacy issues that the change did not introduce, blocking unrelated work.

Why the empty-tree base conflicts with the workflow's diff-scoped contract

The workflow header states the gate is "Diff-scoped: blocks NEW violations without failing on legacy debt" (.github/workflows/governance-enforce.yml:4-5). With BASE set to the empty-tree object, enforce.mjs --changed <empty-tree> runs git diff <base> HEAD, which lists every tracked file as added, so pre-existing violations anywhere in the repo are reported as new. This path is reached whenever github.event.before is all zeros (branch create) or all base inputs are empty. The trade-off may be intentional (fail loud rather than silent), but it changes the gate from diff-scoped to whole-repo in those events and can hard-block pushes for reasons unrelated to the commit.

Open in Devin Review

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

Comment thread .github/workflows/governance-enforce.yml Outdated
…back loud, not raw-git-error

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 2 new potential issues.

Open in Devin Review

Comment on lines +53 to +61
# Indeterminate base: first push (before-SHA is all zeros) or force-push (before-SHA is
# the orphaned old tip, which the clone cannot resolve — hence the cat-file guard; the
# fail-closed enforcer would otherwise hard-fail on a raw git error). Do NOT silently
# scan a partial range — HEAD~1 would skip earlier commits in a multi-commit push and
# let a violation through (a config-no-silent-noop hole). Diff the full tree against
# git's empty-tree object so every introduced file is scanned; loud, never a silent
# empty/partial pass.
BASE=$(git hash-object -t tree /dev/null)
echo "::warning::indeterminate diff base; scanning full tree (empty-tree base) so no commit is skipped"

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 diff-scoped gate into a whole-repo scan

The fallback replaces an unresolvable/zero base with git's empty-tree object, so the enforcer diffs the entire tree and scans every tracked file. That contradicts the workflow header's stated design (.github/workflows/governance-enforce.yml:3-6: "Diff-scoped: blocks NEW violations without failing on legacy debt"). The fallback is reachable on first pushes and force-pushes to main/master, where any pre-existing (legacy) secret-pattern or hardcoded-path finding anywhere in the repo will now hard-fail the required enforce check on the default branch rather than on a PR. The trade-off is deliberate per the inline comment, but it's worth confirming the repo is currently clean under a full-tree scan so a force-push doesn't permanently red the branch.

Open in Devin Review

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


on:
pull_request:
merge_group:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 merge_group trigger added only to this workflow

merge_group is added here but no other workflow in .github/workflows/ (_checks.yml, foundation-gate.yml, go-lint.yml, public-repo-guard.yml) listens for it. If a merge queue is enabled and those checks are also required, merge-queue entries will stall waiting for checks that never report. Either the queue isn't enabled yet (in which case this is a no-op) or the other required workflows need the same trigger.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant