Skip to content

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

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

fix(ci): governance-enforce gate can pass having scanned nothing#34
yakimoto wants to merge 2 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.


Open in Devin Review

Note

Cursor Bugbot is generating a summary for commit 40d3395. 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

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

  • Adds merge_group as a workflow trigger so the gate runs for merge queue events
  • Upgrades @wave-av/governance from ^0.4.4 to ^0.4.6
  • Adds MERGE_BASE_SHA to the enforce step environment; base selection now prefers PR_BASE_SHA, then MERGE_BASE_SHA, then PUSH_BEFORE_SHA
  • Replaces the HEAD~1/HEAD indeterminate-base fallback with the empty-tree object hash (git hash-object -t tree /dev/null), forcing a full-tree scan and emitting a workflow warning instead of silently passing with no files scanned

Macroscope summarized 053f789.

…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_1f8ce220-8a2c-4fff-ba35-fae806748220)

@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: 49 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: 706b9f00-1cac-4b7f-9d7d-3116cf689115

📥 Commits

Reviewing files that changed from the base of the PR and between b1bcde1 and 053f789.

📒 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 6, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 6, 2026

Copy link
Copy Markdown

Approvability

Verdict: Needs human review

Unable to check for correctness in 053f789. Unresolved review comments identify potential bugs: the empty-tree object may not be written to the local git database (missing -w flag), and the merge_group trigger may need to be added to other required workflows. These substantive concerns should be addressed before merging.

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

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fix governance-enforce CI gate to never pass with an empty/partial scan

🐞 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, diff against git empty-tree and warn, ensuring full scan.
Diagram

graph TD
  A["GitHub event"] --> B["governance-enforce.yml"] --> C["Resolve BASE SHA"] --> D{BASE known?} --> E["Diff vs base"] --> F["governance enforce.mjs"]
  D -->|"No"| G["Empty-tree base + warning"] --> E
  D -->|"Yes"| E

  subgraph Legend
    direction LR
    _cfg["Workflow step"] ~~~ _dec{"Decision"} ~~~ _tool["Node CLI"]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Fetch full history and use merge-base
  • ➕ More canonical base selection (e.g., git merge-base HEAD origin/main)
  • ➕ Avoids relying on event payload correctness across triggers
  • ➖ Requires additional checkout configuration (fetch-depth: 0) and more network/time
  • ➖ Still needs careful handling for merge queue / force-push edge cases
2. Always scan full tree (no diff mode)
  • ➕ Simplest correctness model; no base resolution edge cases
  • ➕ Uniform behavior across triggers
  • ➖ Potentially much slower on large repos
  • ➖ Less actionable output if tool assumes changed-only mode

Recommendation: The PR’s approach is a strong, targeted fix for a CI gate: prefer event-provided base SHAs when available, and fail safe by scanning against the empty-tree when not. This prevents the worst-case behavior (green job after scanning nothing) while keeping the common path fast. If future reliability issues appear across unusual events, consider the merge-base + full fetch alternative at the cost of runtime.

Files changed (1) +9 / -2

Bug fix (1) +9 / -2
governance-enforce.ymlFix diff-base resolution and add merge-queue trigger +9/-2

Fix diff-base resolution and add merge-queue trigger

• Adds a 'merge_group' trigger so the governance gate runs in merge queue. Updates base SHA resolution to prefer PR base, then merge-group base, then push-before SHA. Replaces the 'HEAD~1'/'HEAD' fallback with an empty-tree base plus a warning to prevent silent empty or partial scans.

.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 thread .github/workflows/governance-enforce.yml

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 added only to this workflow; other required checks may stall the queue

merge_group is added here, but the other per-commit workflows (.github/workflows/foundation-gate.yml:18-21, _checks.yml, shell-lint.yml) still only trigger on pull_request/push. If a merge queue is enabled and those checks are also required, queued entries will hang waiting for checks that never run. Also note cancel-in-progress: true combined with merge_group: the concurrency group is keyed on github.ref, which is unique per queue entry, so cancellation should not affect queued runs — but confirm this holds if the queue re-forms entries on the same ref.

Open in Devin Review

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

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. Empty-tree hash not written 🐞 Bug ☼ Reliability
Description
The indeterminate-base fallback sets BASE to the empty-tree hash via `git hash-object -t tree
/dev/null` but does not write that tree object into the local object database. If the empty-tree
object is not already present, the downstream enforce.mjs --changed "$BASE" path can fail to
resolve BASE as a git object and the required check will error in first-push/force-push cases.
Code

.github/workflows/governance-enforce.yml[52]

+            BASE=$(git hash-object -t tree /dev/null)
Evidence
The workflow computes BASE from an empty tree hash and then passes it directly to the enforcer
(--changed "$BASE"), so BASE must be a resolvable git object in the local checkout. As written,
git hash-object is invoked without -w, which only prints the hash and does not ensure the object
exists locally for later resolution.

.github/workflows/governance-enforce.yml[46-56]

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 computes the empty-tree ID with `git hash-object -t tree /dev/null` but does not write the object to `.git/objects`. If that object is missing locally, passing the ID to the governance enforcer (`--changed`) can cause git resolution failures.

## Issue Context
This branch is specifically exercised when `BASE` is indeterminate (first push / force-push). The fix should ensure the empty-tree object is guaranteed to exist locally before it is used as a diff base.

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

## Suggested change
Change:
- `BASE=$(git hash-object -t tree /dev/null)`

To one of:
- `BASE=$(git hash-object -t tree -w /dev/null)`
- `BASE=$(git mktree </dev/null)`

Either approach guarantees the object exists for subsequent git operations.

ⓘ 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 is a localized two-hunk CI workflow change, but it alters a governance/security gate’s diff-base resolution and merge-queue behavior, warranting a careful single-pass review.

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

Qodo Logo

# 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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Empty-tree hash not written 🐞 Bug ☼ Reliability

The indeterminate-base fallback sets BASE to the empty-tree hash via `git hash-object -t tree
/dev/null` but does not write that tree object into the local object database. If the empty-tree
object is not already present, the downstream enforce.mjs --changed "$BASE" path can fail to
resolve BASE as a git object and the required check will error in first-push/force-push cases.
Agent Prompt
## Issue description
The workflow computes the empty-tree ID with `git hash-object -t tree /dev/null` but does not write the object to `.git/objects`. If that object is missing locally, passing the ID to the governance enforcer (`--changed`) can cause git resolution failures.

## Issue Context
This branch is specifically exercised when `BASE` is indeterminate (first push / force-push). The fix should ensure the empty-tree object is guaranteed to exist locally before it is used as a diff base.

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

## Suggested change
Change:
- `BASE=$(git hash-object -t tree /dev/null)`

To one of:
- `BASE=$(git hash-object -t tree -w /dev/null)`
- `BASE=$(git mktree </dev/null)`

Either approach guarantees the object exists for subsequent git operations.

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

@qodo-code-review

Copy link
Copy Markdown

Qodo Fixer

✅ Merged (0) · ☑ Fixed (0)

Process

  • No fixes were applied (no_fixes_applied)

… fail open

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
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