fix(validate-go-project): scan for vulnerabilities on the default branch - #779
Conversation
The govulncheck job carried `github.event_name == 'pull_request'`, so it never ran on the default branch in any consumer repo. A vulnerability scan's verdict depends on the vulnerability database as well as the diff, so an advisory published after a merge makes already-merged, unchanged code vulnerable — and a pull_request-only scan structurally cannot report that. Measured on ksail: GO-2026-6061 (reachable, google.golang.org/grpc < v1.82.1) was published 2026-07-27T15:30Z against a dependency main already pinned. main kept reporting green; the advisory surfaced only as a failure on unrelated PRs. Separately, `.govulncheck-allow.txt` was missing from the `go` path filter, so a commit whose only purpose is to change which advisories the gate accepts skipped the gate that reads it (ksail c3522e89: allowlist-only push to main → scan skipped). Both are trigger-condition regressions that leave a consumer's default branch silently unscanned, so a contract self-test now asserts them. Part of devantler-tech/ksail#6373
✅MegaLinter analysis: Success
Notices📣 MegaLinter 9.5.0 is out! Discover the new features and security recommendations in the release announcement. (Skip this info by defining See detailed reports in MegaLinter artifacts Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining
|
@coderabbitai review |
|
✅ Action performedReview finished.
|
📝 WalkthroughWalkthroughThe Go path filter now includes root and nested Possibly related issues
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
CodeRabbit reported "Review limit reached" at |
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 44ca39bd84
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex review on #779 found the fix was incomplete in the same way the fix itself describes, plus a guard that could not detect it. Removing `event_name == 'pull_request'` let the default branch reach the scan, but `needs.changes.outputs.go` still gated it. A default-branch push touching no Go path (a README edit) therefore leaves the scan skipped, and the branch keeps reporting green while a newly-published advisory already applies to its unchanged code — the same time-vs-diff error one level down. The path filter is now OR-ed with a default-branch clause: on the default branch every invocation scans; on pull requests and topic branches the path filter still applies, so per-PR cost is unchanged. The guard asserted only the ABSENCE of one forbidden expression, so it passed a workflow restricted to `workflow_dispatch` while printing a success message claiming default-branch coverage (verified against the previous test). It now asserts the intended condition positively: no event_name equality at all, a default-branch clause present, and the path filter OR-ed with it rather than AND-ed alongside. Six ablations, each RED. `.govulncheck-allow.txt` also matched only at the repo root, so an allowlist edit inside a nested module selected by `working-directory` skipped the scan that reads it; the nested pattern is now covered too.
@coderabbitai review |
|
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/tests/test-govulncheck-main-coverage.sh:
- Around line 33-42: Add a negative self-test alongside the existing test flow
in the script, invoking it with a deliberately invalid fixture workflow kept
outside the gate’s normal scan scope. Assert that the guard exits non-zero and
emits the expected finding, covering event-gated if conditions or disallowed go
filters while preserving the current positive self-test.
- Around line 93-110: Extend Check 3 in the test’s top-level condition
validation to whitelist ref-related predicates: reject any top-level conjunct
referencing github.ref or github.event_name unless it belongs to the OR-group
containing the default_branch clause. Preserve the existing path-filter grouping
checks, and ensure predicates such as ref exclusions or release-only checks
cause the guard to fail.
In @.github/workflows/validate-go-project.yaml:
- Around line 387-390: Update the remaining self-repository exclusion checks in
the workflow’s downstream job conditions to use “devantler-tech/actions” instead
of “devantler-tech/reusable-workflows”. Keep the existing changes and
default-branch conditions unchanged so dependency failures remain visible in the
aggregate result.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: c281ad98-3890-4c5a-bf78-f490814e08c5
📒 Files selected for processing (3)
.github/tests/test-govulncheck-main-coverage.sh.github/workflows/ci.yaml.github/workflows/validate-go-project.yaml
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
.github/tests/**
📄 CodeRabbit inference engine (AGENTS.md)
Place deliberately bad fixtures for gating-workflow tests outside the gate's normal scan scope.
Files:
.github/tests/test-govulncheck-main-coverage.sh
.github/workflows/*.yaml
📄 CodeRabbit inference engine (AGENTS.md)
.github/workflows/*.yaml: Keep all GitHub Actions workflows under.github/workflows/.
Reusable workflows must use theworkflow_calltrigger.
Pin every remote action reference to a full commit SHA with a version comment; do not use remote self-references.
Includestep-security/harden-runneras the first step of every reusable-workflow job, withegress-policy: audit.
Set top-level workflow permissions to{}and grant permissions per job.
Setpersist-credentials: falseonactions/checkoutunless the job must push.
Workflows used as organization-level rulesets must includepull_requestandmerge_grouptriggers in addition toworkflow_call.
For reusable workflows referencing a sibling action, check out the workflow repository at${{ job.workflow_sha }}into.devantler-tech-actions, then invoke the action locally; remove the checkout before workspace-wide scans or commits.
New reusable-workflow jobs, steps, or behaviors must be behind a default-off boolean opt-in input and guarded withif: ${{ inputs.<enable-x> }}.
When a workflow supports bothworkflow_dispatchandworkflow_call, normalize boolean inputs withinputs.<enable-x> == true || inputs.<enable-x> == 'true'.
Test both enabled and disabled states of every feature flag with CI test jobs.
Gating reusable workflows must have both a passing self-test and a failing-input self-test that verifies the expected finding; non-gating workflows require happy-path coverage.
Preserve tested consumer contracts, such asvalidate-go-project.yamlhonoring.govulncheck-allow.txt; update the corresponding self-tests whenever the implementation changes.
Files:
.github/workflows/ci.yaml.github/workflows/validate-go-project.yaml
.github/workflows/ci.yaml
📄 CodeRabbit inference engine (AGENTS.md)
.github/workflows/ci.yaml: Add a test job for every action and reusable workflow, using local paths such asuses: ./<action>oruses: ./.github/workflows/<workflow>.yaml.
Wire every new test job intoci-required-checksboth throughneeds:and thejob-resultsinput ofaggregate-job-checks.
Files:
.github/workflows/ci.yaml
🔇 Additional comments (4)
.github/workflows/validate-go-project.yaml (1)
75-82: LGTM!.github/tests/test-govulncheck-main-coverage.sh (2)
113-136: LGTM!
46-47: 🩺 Stability & AvailabilityNo change needed for
yq -r.The repository uses mikefarah
yqconsistently with-r, and scalar extraction already returns raw strings from the installed runner image.> Likely an incorrect or invalid review comment..github/workflows/ci.yaml (1)
2235-2253: LGTM!Also applies to: 2745-2745, 2836-2836
…guard CodeRabbit review on #779. The trigger guard is itself a gate, and its checks are structural string analysis over a GitHub expression — unusually easy to make silently vacuous. Per this repo's both-tests convention it now has a blocks-on-bad-input counterpart: five fixtures, one per failure mode, each asserted to fail WITH THE EXPECTED MESSAGE so an operational error cannot false-pass. It also asserts the guard still passes the real workflow, so a reject-everything guard fails too. That sanity arm immediately caught a real regression while being written. Check 3 did not catch the "ref predicate that excludes the default branch" case the file's own header claims to catch: a top-level `&& github.ref != 'refs/heads/main'` satisfied every assertion while making default-branch runs unreachable. Top-level ref predicates are now rejected — the legitimate default-branch clause lives inside the OR-group and has already been stripped by that point, so anything left is an extra conjunct. The group extraction used a regex bounded with `[^()]*`, which cannot match a group containing nested parentheses and so silently returned the innermost one. Replaced with a balance scan that takes the outermost group. The govulncheck gate's default-branch arm now tests `go == 'false'` rather than being unconditional. An empty output means the `changes` job did not run at all; only an explicit 'false' proves the filter ran and found no Go paths. Keying on the explicit value keeps the gate independent of how skipped-needs propagate, which is the substance of the third review finding.
Verification recordExercised the gate's real behaviour rather than reasoning about it. A trigger condition has no cheap runtime surface — I cannot push to a consumer's Before (
Exactly one row changes, and it is the defect row. That is the whole claim of this PR, stated as a diff rather than a description:
Also verified in real CI at |
@coderabbitai review |
|
✅ Action performedReview finished.
|
CodeRabbit reports "Review limit reached … we couldn't start this review", next review available in 41 minutes. Its command reply said "Review finished" — that is the acknowledgement, not the outcome; the limit is stated only in the summary body. No review object or inline comment was produced at this head. A stated retry window still means the lane is not delivering now, so advancing to Codex rather than parking a finished change behind a provider's quota. |
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 30552d63c2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…n opt-in input The default-branch scan changes behaviour in every consumer repository at once, and its intended consequence is that a green default branch can go red. Per AGENTS.md (*Shipping a new capability behind an opt-in flag*) it now ships behind `scan-default-branch`, default false, to be rolled out caller-by-caller before the default flips and the input is removed (#788). With the flag off, the gate reproduces the behaviour shipped today: the scan runs on pull requests when the path filter matches, and nowhere else. Also isolates the allowlist trigger. `.govulncheck-allow.txt` was added to the shared `go` filter, whose output go-mod-tidy, golangci-lint, deadcode, the test matrix and coverage all consume — so an allowlist-only commit ran all of them in every consumer, and an administrative risk-acceptance could be blocked by an unrelated pre-existing failure. It now has its own `govulncheck` filter output, OR-ed into this job alone. The trigger guard is re-aimed at the flagged shape. It no longer rejects any `event_name` equality (the flag-off arm legitimately carries one) but rejects a TOP-LEVEL one, and adds the backward-compatibility property directly: every OR-arm the input does not gate must still be restricted to pull requests, so a caller that passes nothing cannot acquire new behaviour. The input must also exist, be boolean, and default to false. Fixtures are now generated from one base by generate.sh, so each differs from `good.yaml` only in its defect, and `good.yaml` is asserted to PASS — a guard that rejects everything fails the suite just as a guard that accepts everything does. Every assertion and helper was ablated independently; all 16 go red.
…arameters Adding the `scan-default-branch` both-states self-test reintroduced actions#587 in a new form. The two [Test] jobs call this reusable workflow from the SAME caller workflow on the SAME ref, differing only by one input, so they computed an identical concurrency group and `cancel-in-progress` made the second cancel the first: nine jobs of the flag-off invocation were cancelled and CI - Required Checks went red. `github.workflow` separates a caller's self-test from the org-required direct run, but it cannot separate two calls from the same caller. The group now also carries the invocation's inputs, so two invocations differing in any input are different logical invocations. Only reruns of the same invocation still supersede. Adding a discriminator can only split groups further, never merge two that were separate, so this direction of change cannot reintroduce #587 itself. The lockstep guard is strengthened accordingly: it now reads the workflow_call input list and requires EVERY input to appear in the group, so a future input that distinguishes two invocations cannot be added without also distinguishing their groups. Verified positive, plus three ablations (drop the flag, drop pr-owner, drop github.workflow) each going red, and a fourth confirming that adding a new input while leaving the group alone fails the guard.
@coderabbitai review |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== PR metadata =='
gh pr view 779 --repo devantler-tech/actions \
--json number,title,baseRefName,headRefName,headRefOid,files \
--jq '{number, title, baseRefName, headRefName, headRefOid, files: [.files[].path]}'
echo
echo '== Merge-base and changed files =='
base_ref="$(gh pr view 779 --repo devantler-tech/actions --json baseRefOid --jq '.baseRefOid')"
printf 'base=%s\nhead=%s\n' "$base_ref" "$(git rev-parse HEAD)"
git diff --name-status "$base_ref"...HEAD
git diff --check "$base_ref"...HEAD
echo
echo '== Structural outlines =='
ast-grep outline .github/workflows/validate-go-project.yaml --items all || true
ast-grep outline .github/workflows/ci.yaml --items all || true
echo
echo '== Changed workflow and test content =='
git diff --unified=80 "$base_ref"...HEAD -- \
.github/workflows/validate-go-project.yaml \
.github/workflows/ci.yaml \
.github/tests/test-govulncheck-main-coverage.sh \
.github/tests/test-govulncheck-trigger-guard-blocks-on-bad-input.shLength of output: 82853 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== Relevant workflow sections =='
nl -ba .github/workflows/validate-go-project.yaml | sed -n '1,180p'
nl -ba .github/workflows/validate-go-project.yaml | sed -n '330,470p'
echo
echo '== Contract-test harnesses =='
nl -ba .github/tests/test-govulncheck-main-coverage-blocks.sh
printf '\n-- main guard (remainder / closing section) --\n'
nl -ba .github/tests/test-govulncheck-main-coverage.sh | sed -n '150,310p'
echo
echo '== Fixture inventory and content =='
for f in .github/tests/govulncheck-main-coverage-fixture/*; do
printf '\n--- %s ---\n' "$f"
nl -ba "$f"
done
echo
echo '== All reusable-workflow call sites and input references =='
rg -n -C 5 --glob '*.y*ml' \
'(uses:[[:space:]]*\./\.github/workflows/validate-go-project\.yaml|uses:[[:space:]]*devantler-tech/actions/\.github/workflows/validate-go-project\.yaml|scan-default-branch)' \
.
echo
echo '== README changes =='
git diff --unified=50 "$(git merge-base HEAD origin/main)"...HEAD -- README.md
echo
echo '== YAML parse / expression reference checks =='
yq -e '.' .github/workflows/validate-go-project.yaml >/dev/null
yq -e '.' .github/workflows/ci.yaml >/dev/null
rg -n -C 2 'govulncheck|changes\.outputs\.govulncheck|changes\.outputs\.go|scan-default-branch' \
.github/workflows/validate-go-project.yaml .github/workflows/ci.yamlLength of output: 1726 🏁 Script executed: #!/bin/bash
set -euo pipefail
number() { awk '{printf "%6d\t%s\n", NR, $0}'; }
slice() { awk -v start="$2" -v end="$3" 'NR >= start && NR <= end {printf "%6d\t%s\n", NR, $0}' "$1"; }
echo '== Relevant workflow sections =='
slice .github/workflows/validate-go-project.yaml 1 180
slice .github/workflows/validate-go-project.yaml 330 470
echo
echo '== Contract-test harnesses =='
number < .github/tests/test-govulncheck-main-coverage-blocks.sh
printf '\n-- main guard (remainder / closing section) --\n'
slice .github/tests/test-govulncheck-main-coverage.sh 150 310
echo
echo '== Fixture inventory and content =='
for f in .github/tests/govulncheck-main-coverage-fixture/*; do
printf '\n--- %s ---\n' "$f"
number < "$f"
done
echo
echo '== All reusable-workflow call sites and input references =='
rg -n -C 5 --glob '*.y*ml' \
'(uses:[[:space:]]*\./\.github/workflows/validate-go-project\.yaml|uses:[[:space:]]*devantler-tech/actions/\.github/workflows/validate-go-project\.yaml|scan-default-branch)' \
.
echo
echo '== README changes =='
base_ref="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
git diff --unified=50 "$base_ref"...HEAD -- README.md
echo
echo '== YAML parse / expression reference checks =='
yq -e '.' .github/workflows/validate-go-project.yaml >/dev/null
yq -e '.' .github/workflows/ci.yaml >/dev/null
echo 'YAML parse: OK'
rg -n -C 2 'govulncheck|changes\.outputs\.govulncheck|changes\.outputs\.go|scan-default-branch' \
.github/workflows/validate-go-project.yaml .github/workflows/ci.yamlLength of output: 74479 🏁 Script executed: #!/bin/bash
set -euo pipefail
base_ref="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
echo '== README diff =='
git diff --unified=80 "$base_ref"...HEAD -- README.md
echo
echo '== CI additions and required-check aggregation =='
git diff --unified=35 "$base_ref"...HEAD -- .github/workflows/ci.yaml | \
sed -n '/test-validate-go-project-scan-default-branch/,+90p; /test-govulncheck-main-coverage:/,+130p; /ci-required-checks:/,+230p'
echo
echo '== Reusable-workflow invocations and all new-input references =='
grep -RInE \
'(validate-go-project\.ya?ml|scan-default-branch)' \
--include='*.yaml' --include='*.yml' .github README.md || true
echo
echo '== YAML parser checks =='
yq -e '.' .github/workflows/validate-go-project.yaml >/dev/null
yq -e '.' .github/workflows/ci.yaml >/dev/null
echo 'YAML parse: OK'
echo
echo '== PR checks and review comments =='
gh pr view 779 --repo devantler-tech/actions \
--json statusCheckRollup,reviews,comments \
--jq '{
checks: [.statusCheckRollup[]? | {name: .name, conclusion: .conclusion, status: .status}],
reviews: [.reviews[]? | {author: .author.login, state: .state, body: .body}],
comments: [.comments[]? | {author: .author.login, body: .body}]
}'
echo
echo '== Whitespace errors =='
git diff --check "$base_ref"...HEADLength of output: 35807 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== Pull request status =='
gh pr view 779 --repo devantler-tech/actions \
--json headRefOid,mergeable,reviewDecision,statusCheckRollup \
--jq '{
head: .headRefOid,
mergeable,
reviewDecision,
checks: [
.statusCheckRollup[]? |
{
name: .name,
status: .status,
conclusion: .conclusion,
detailsUrl: .detailsUrl
}
]
}'
echo
echo '== Existing reviews and inline review comments =='
gh api "repos/devantler-tech/actions/pulls/779/reviews" \
--jq '.[] | {user: .user.login, state: .state, body: .body}' || true
gh api "repos/devantler-tech/actions/pulls/779/comments" \
--jq '.[] | {user: .user.login, path: .path, line: .line, body: .body}' || trueLength of output: 80901
One documentation follow-up: |
CodeRabbit acknowledged the request for |
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d7eb17b71
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…an at the right allowlist Codex review on #779 raised three findings at 9d7eb17; all three verified against the code and fixed here. P1 — the allowlist trigger was not opt-in. Adding `needs.changes.outputs.govulncheck` to the pull-request arm scheduled the 20-minute scan for every consumer the moment this merges, including callers that pass nothing. AGENTS.md requires new behaviour behind a default-off input with zero change for callers that omit it, so the allowlist term is now AND-ed with `inputs.scan-default-branch` and the input's description covers both behaviours it gates. P1 — the scan did not read the allowlist that triggered it. The new `**/.govulncheck-allow.txt` pattern lets a nested module's allowlist fire the scan, but `allow-file` was a bare checkout-root-relative literal. The action resolves its path inputs from the checkout root, not from `work-dir` — pinned by the allowlist self-test in ci.yaml, which passes `work-dir: .github/tests/govulncheck-allowlist` alongside a fully prefixed `allow-file`. `defaults.run.working-directory` does not close the gap either: it governs `run:` steps only, so the detection step saw the nested file while the scanner was sent to the root. It is now composed from `inputs.working-directory`, matching the sibling `go-version-file` input. P2 — the guard proved neither property. Measured: the suite passed unchanged on the pre-fix head while printing "nothing new runs unopted, and allowlist edits trigger the scan that reads them", so it asserted exactly the two properties that were violated. Two checks are added. Check 9 requires the innermost parenthesised group holding the allowlist term to also hold the flag, AND-ed — a co-occurrence test would accept `(flag || govulncheck == 'true')`, where the trigger fires with the flag off. Check 10 requires `allow-file` to be composed from `inputs.working-directory`. Both are pinned by new bad fixtures (`allowlist-trigger-not-flag-gated`, `allow-file-not-working-dir-relative`) so the blocks test proves they bite in CI, not only locally. The fixture generator now models the action step, and every fixture's pull-request arm carries the gated form so each still differs from the control in exactly one field — except `flag-not-referenced`, which keeps the ungated arm on purpose, since injecting the flag there would stop the assertion it exists to pin from firing. Verified: both self-tests green; each fix independently ablated back to RED with the matching diagnostic; actionlint 3 findings at head against 3 at the merge-base (all pre-existing, lines 790/873/874); shellcheck clean.
All three Codex findings at P1 — allowlist trigger not opt-in. Valid. Confirmed the input is new in this PR and defaults to P1 — nested allowlist not read by the scanner. Valid, and confirmed from this repo rather than P2 — the guard proved neither property. Valid, and worse than reported. Measured directly: the Two checks were added rather than one. Check 9 requires the innermost parenthesised group holding the Both are pinned by new bad fixtures — Verification: both self-tests green; gating ablated → check 9 fires; |
All three findings from the previous review are fixed in @coderabbitai review |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
base_ref="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
printf '== Revisions ==\nbase=%s\nhead=%s\n' "$base_ref" "$(git rev-parse HEAD)"
printf '\n== Changed files and whitespace ==\n'
git diff --name-status "$base_ref"...HEAD
git diff --check "$base_ref"...HEAD
printf '\n== Changed workflow and contract-test diff ==\n'
git diff --unified=100 "$base_ref"...HEAD -- \
.github/workflows/validate-go-project.yaml \
.github/workflows/ci.yaml \
.github/tests/test-govulncheck-main-coverage.sh \
.github/tests/test-govulncheck-main-coverage-blocks.sh \
.github/tests/govulncheck-main-coverage-fixture
printf '\n== Workflow outline ==\n'
ast-grep outline .github/workflows/validate-go-project.yaml --items all || true
printf '\n== Relevant workflow sections ==\n'
rg -n -C 12 \
'scan-default-branch|govulncheck|allow-file|working-directory|paths-filter|\.govulncheck-allow' \
.github/workflows/validate-go-project.yaml .github/workflows/ci.yaml
printf '\n== Contract-test sources and fixtures ==\n'
fd -t f . .github/tests/govulncheck-main-coverage-fixture .github/tests 2>/dev/null | \
sort | grep -E 'govulncheck-(main-coverage|trigger-guard)|govulncheck-main-coverage-fixture' | \
while IFS= read -r file; do
printf '\n--- %s ---\n' "$file"
nl -ba "$file"
done
printf '\n== Reusable workflow call sites and input usages ==\n'
rg -n -C 6 --glob '*.yml' --glob '*.yaml' \
'(uses:[[:space:]]*(\./)?\.github/workflows/validate-go-project\.yaml|scan-default-branch:|allow-file:|working-directory:)' \
.
printf '\n== YAML parse ==\n'
yq -e '.' .github/workflows/validate-go-project.yaml >/dev/null
yq -e '.' .github/workflows/ci.yaml >/dev/null
echo 'YAML parse: OK'
printf '\n== Current PR status and review artifacts ==\n'
gh pr view 779 --repo devantler-tech/actions \
--json headRefOid,mergeable,reviewDecision,statusCheckRollup \
--jq '{
head: .headRefOid,
mergeable,
reviewDecision,
checks: [.statusCheckRollup[]? | {name, status, conclusion}]
}'
gh api 'repos/devantler-tech/actions/pulls/779/comments' \
--jq '.[] | {user: .user.login, path, line, body}' || trueLength of output: 181822 🏁 Script executed: #!/bin/bash
set -euo pipefail
number() { awk '{printf "%6d %s\n", NR, $0}'; }
printf '== Contract guard ==\n'
number < .github/tests/test-govulncheck-main-coverage.sh
printf '\n== Negative-fixture runner ==\n'
number < .github/tests/test-govulncheck-main-coverage-blocks.sh
printf '\n== Fixture contents ==\n'
for file in .github/tests/govulncheck-main-coverage-fixture/*; do
[ -f "$file" ] || continue
printf '\n--- %s ---\n' "$file"
number < "$file"
done
printf '\n== Relevant CI job definitions ==\n'
awk 'NR >= 2000 && NR <= 2050 {printf "%6d %s\n", NR, $0}
NR >= 2408 && NR <= 2462 {printf "%6d %s\n", NR, $0}
NR >= 2735 && NR <= 2785 {printf "%6d %s\n", NR, $0}
NR >= 2920 && NR <= 3080 {printf "%6d %s\n", NR, $0}' \
.github/workflows/ci.yaml
printf '\n== All validate-go-project reusable-workflow callers ==\n'
rg -n -C 8 --glob '*.yaml' --glob '*.yml' \
'uses:[[:space:]]*(\./)?\.github/workflows/validate-go-project\.yaml' .
printf '\n== Guard-related symbols outside the guard and fixtures ==\n'
rg -n -C 3 \
'scan-default-branch|outputs\.govulncheck|allow-file:.*working-directory|govulncheck-main-coverage' \
.github --glob '!tests/test-govulncheck-main-coverage.sh' \
--glob '!tests/test-govulncheck-main-coverage-blocks.sh' \
--glob '!tests/govulncheck-main-coverage-fixture/**'
printf '\n== YAML parsing ==\n'
yq -e '.' .github/workflows/validate-go-project.yaml >/dev/null
yq -e '.' .github/workflows/ci.yaml >/dev/null
echo 'YAML parse: OK'
printf '\n== Current PR checks/review decision ==\n'
gh pr view 779 --repo devantler-tech/actions \
--json headRefOid,mergeable,reviewDecision,statusCheckRollup \
--jq '{
head: .headRefOid,
mergeable,
reviewDecision,
checks: [.statusCheckRollup[]? | {name, status, conclusion}]
}'Length of output: 107001 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '== Reusable workflow references ==\n'
rg -n -C 4 --glob '*.yaml' --glob '*.yml' \
'validate-go-project\.yaml' . || true
printf '\n== Workflow-call input declarations ==\n'
yq -r '.["on"].workflow_call.inputs | to_entries[] |
"\(.key): type=\(.value.type), default=\(.value.default // "<none>")"' \
.github/workflows/validate-go-project.yaml
printf '\n== YAML parse ==\n'
yq -e '.' .github/workflows/validate-go-project.yaml >/dev/null
yq -e '.' .github/workflows/ci.yaml >/dev/null
echo 'YAML parse: OK'
printf '\n== Current PR status ==\n'
gh pr view 779 --repo devantler-tech/actions \
--json headRefOid,mergeable,reviewDecision,statusCheckRollup \
--jq '{
head: .headRefOid,
mergeable,
reviewDecision,
non_green: [
.statusCheckRollup[]? |
select(
.status != "COMPLETED"
or (.conclusion != "SUCCESS" and .conclusion != "SKIPPED" and .conclusion != "NEUTRAL")
) |
{name, status, conclusion}
],
govulncheck_checks: [
.statusCheckRollup[]? |
select(.name | test("Govulncheck|Validate Go Project - Default-Branch"; "i")) |
{name, status, conclusion}
]
}'
printf '\n== Existing inline review comments at latest head ==\n'
gh api 'repos/devantler-tech/actions/pulls/779/comments' \
--jq '.[] | {user: .user.login, commit_id, path, line, body}' || trueLength of output: 1811 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '== Current PR status ==\n'
gh pr view 779 --repo devantler-tech/actions \
--json headRefOid,mergeable,reviewDecision,statusCheckRollup \
--jq '{
head: .headRefOid,
mergeable,
reviewDecision,
non_green: [
.statusCheckRollup[]? |
select(
.status != "COMPLETED"
or (.conclusion != "SUCCESS" and .conclusion != "SKIPPED" and .conclusion != "NEUTRAL")
) |
{name, status, conclusion}
],
govulncheck_checks: [
.statusCheckRollup[]? |
select(.name | test("Govulncheck|Validate Go Project - Default-Branch"; "i")) |
{name, status, conclusion}
]
}'
printf '\n== Inline review comments ==\n'
gh api 'repos/devantler-tech/actions/pulls/779/comments' \
--jq '.[] | {user: .user.login, commit_id, path, line, body}' || true
printf '\n== Review states ==\n'
gh api 'repos/devantler-tech/actions/pulls/779/reviews' \
--jq '.[] | {user: .user.login, commit_id, state, body}' || trueLength of output: 1403 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh pr view 779 --repo devantler-tech/actions \
--json headRefOid,mergeable,reviewDecision,statusCheckRollup \
--jq '{
head: .headRefOid,
mergeable,
reviewDecision,
non_green: [
.statusCheckRollup[]? |
select(
.status != "COMPLETED"
or (.conclusion != "SUCCESS" and .conclusion != "SKIPPED" and .conclusion != "NEUTRAL")
) |
{name: (.name // "<unnamed>"), status, conclusion}
],
relevant_checks: [
.statusCheckRollup[]? |
select((.name // "") | test("Govulncheck|Validate Go Project - Default-Branch"; "i")) |
{name, status, conclusion}
]
}'
printf '\n== Inline review comments ==\n'
gh api 'repos/devantler-tech/actions/pulls/779/comments' \
--jq '.[] | {user: .user.login, commit_id, path, line, body}' || trueLength of output: 58139
The corrected default-off opt-in, dedicated allowlist filter, working-directory-relative |
CodeRabbit produced no gate-satisfying artifact at this head — advancing to Codex. It was requested at @codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6d357b4ca7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex's P2 at this head is answered and its thread resolved. The resolution changed no file by design — the requested pre-merge exercise cannot exist in a Skipping CodeRabbit on account-wide evidence rather than on this PR's history. Its per-developer quota is exhausted right now: a request on @codex review |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Readiness evaluation — promoting1. Programmatically tested. All checks green, 0 failing, 0 pending; 2. Reviewed. Codex green at 3. Tried and evaluated as a user — with a stated limit. The two halves differ:
Outstanding post-merge verification — merge is not the proof. That caller pins this workflow by SHA ( |
Correction to the post-merge verification I named above — merged as I described the outstanding check as " The correct sequence to verify is therefore: release here → consumer bumps the pin → consumer opts in with The half that is live for every consumer at the bumped pin, with no flag, is the path-filter fix: an allowlist-only change now triggers the scan that reads it. |

Why
A Go repository's default branch could report green while its vulnerability scan had not run — so the portfolio learned about a live vulnerability from unrelated pull requests failing, rather than from the branch that was actually vulnerable.
This is not theoretical. An advisory published against a dependency KSail already pinned made KSail's
mainvulnerable without a single line changing.mainkept showing green, and the first anyone saw of it was two unrelated pull requests going red for something their authors had not done.A second, smaller gap sits next to it: changing the allowlist that decides which advisories are accepted skipped the very scan that reads it.
What
The allowlist fix applies immediately. Editing the allowlist now re-runs the vulnerability scan — and only that scan, so an administrative decision to accept an advisory can't be held up by an unrelated failure elsewhere in the repo.
Default-branch scanning ships switched off. The scan can now run on every default-branch invocation rather than only when Go files happen to change — which is what closes the gap, because a scan's answer depends on the published advisory database as much as on the code. But turning that on means a default branch that was green can go red without anyone changing anything, in every consumer at once. So it is an opt-in setting, defaulting to off: a consumer that passes nothing behaves exactly as it does today.
Rolling it out consumer by consumer, then making it the default and removing the switch, is tracked in #788.
Notes for review
Fixes #758
Part of #757
Part of devantler-tech/ksail#6373