fix(ci): stop the Trivy check going red on a missing SARIF configuration - #818
Merged
Conversation
The "Trivy" check has been failing or going neutral on every PR with:
Warning: 1 configuration present on refs/heads/master was not found:
.github/workflows/ci.yml:security-scan
With no complete baseline to diff against, code scanning then reports
PRE-EXISTING findings as "new alerts" — a red check that no code change
can clear. It is currently red on #813, #814 and #816, none of which
touch anything it scans.
Two separate causes, both fixed here.
1. The real one: a 6-minute job sharing a tool identity with 25-second
ones.
GitHub creates ONE check run per SARIF *tool*, aggregating every
configuration reporting under that name. Trivy writes
tool.driver.name = "Trivy" into every SARIF, so security.yml's
CONTAINER scan — which builds two images first and takes ~6 minutes —
landed in the same check as the filesystem scans that finish in ~25
seconds. The check was finalised long before the slow configuration
reported.
security.yml now retags its SARIF to "Trivy Container" before upload,
giving it its own check run. Nothing stops being scanned; the findings
report under a different tool name.
2. The one an earlier fix introduced: a baseline entry with nothing
producing it.
Removing ci.yml's upload (#647) did not fix the warning — it only
changed WHICH configuration goes missing. Master's baseline still holds
the analysis that step produced, and nothing re-registers it. The entry
cannot be aged out from the repo, and deleting it needs code-scanning
admin scope (the API returns 403 here), so the only in-repo fix is to
produce the configuration again.
The upload is restored with NO explicit category, reproducing the exact
analysis key the baseline expects. ref/sha are deliberately left to
upload-sarif's own detection rather than hand-rolled, per the warning
already in harden-gate.yml.
Net result: tool "Trivy" holds exactly the two fast filesystem
configurations, which finish within seconds of each other, and both are
registered on master and on PRs. The slow container scan reports
separately as "Trivy Container".
No severity filter, ignore rule, or exit code is changed. Nothing is
excluded from scanning and no finding is suppressed — this only fixes
which check a finding is reported under and whether the diff has a
baseline.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013tMciHkPE8To7V67CsgKKc
7 tasks
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
This was referenced Aug 26, 2026
8 tasks
5 tasks
izzywdev
added a commit
that referenced
this pull request
Aug 27, 2026
The stranded-branch detector's create path went live when can_approve_pull_request_reviews was flipped to true on 2026-08-23, and started opening PRs. Those PRs could not merge. GitHub does not trigger workflow runs from events raised by GITHUB_TOKEN, so a PR opened with it gets no pull_request runs at all — no gates, no auto-merge job. This workflow also applies the auto-merge label, so the result is a PR that looks handled and is blocked forever on checks that will never start. Observed on #815, #817, #818 and again on #821-#830, each sitting at exactly one check until closed and reopened by hand, at which point 40+ checks appeared immediately. Fixes: - Create the PR with GH_RELEASE_PAT (an ordinary user event, which does trigger CI), falling back to GITHUB_TOKEN so an unset secret degrades rather than breaks the job. - If the fallback is taken, fail loudly with the PR number, the close/reopen command that unsticks it, and the secret to set. Creating a PR that cannot merge is not a success. The header claimed this workflow "CANNOT open a pull request on this repo, and never has" — true until 2026-08-23, and the reason nobody noticed: it told readers the workflow did nothing while it was opening unmergeable PRs. Corrected in place, with the original tradeoff kept as a historical note.
claude Bot
added a commit
that referenced
this pull request
Aug 27, 2026
Issue #286: the branch ruleset's required status check "In-repo packages resolve from source" was produced by workspace-deps-check.yml, which was path-filtered to `**/package.json`. A path-filtered workflow never runs on a PR that touches none of its paths, so the check run is never created -- and GitHub treats a required-but-never-reported context as unsatisfied. Every PR that didn't touch a package.json sat permanently at "Expected -- waiting for status to be reported", with no red to click and nothing to re-run. That's why every merge needed --admin, defeating the auto-merge path CLAUDE.md documents. VERIFIED FIRST, PER INSTRUCTIONS: this exact defect no longer reproduces on master. - workspace-deps-check.yml's `on.pull_request` carries no `paths:` key today -- confirmed by reading the file at origin/master (2de4a1c). - The ruleset ("Protect Master", id 17974934) still requires the "In-repo packages resolve from source" context -- confirmed via `gh api repos/izzywdev/FuzeFront/rulesets/17974934` (branch-protection API 403'd for this token as anticipated, but the rulesets API worked). - Empirically confirmed on merged PR #818, which touches no package.json file: `In-repo packages resolve from source: success` is present in its check-runs, and the PR merged cleanly. - git blame shows the filter was already removed by #794 (2026-08-23, "ci: two required checks on master cannot deliver a correct verdict"), which chose exactly fix (a) from this issue's own writeup ("Always run, skip the work -- keeps the gate honest") over the path-filter- shim alternative, because the job is dependency-free and scans 49 manifests in under a second, so running it unconditionally costs nothing. That reasoning is sound and is not being revisited here. So there is no live code defect left in scope of #286 to fix -- #794 already applied the correct one of the two standard fixes and did not weaken the required set. What #286 leaves genuinely open is that nothing stops the exact same regression from recurring: the "no paths: filter" invariant lived only in prose (two workflow header comments) with no CI enforcement, for either of the two workflows whose comments state it (workspace-deps-check.yml, gate-sealed-keys.yml). This commit turns that prose into an enforced, dependency-free gate: - governance/required-check-triggers.json declares the (context, workflow file) pairs that must always run unconditionally on pull_request. - scripts/check-required-check-triggers.mjs scans each declared workflow for a paths:/paths-ignore: filter nested under its pull_request: trigger and fails if one is present. No YAML-parser dependency (same style as check-workspace-deps.mjs) -- a line-based indentation scan is enough for the one shape that matters, and it does not false-positive on an unrelated paths: filter under a sibling push: trigger (tested). - .github/workflows/gate-required-check-triggers.yml wires it in on every PR to master, itself with NO paths: filter -- it would be exactly the bug it exists to catch if it were path-filtered. Mutation-tested: re-adding the historical `paths: ['**/package.json', ...]` block to workspace-deps-check.yml's pull_request trigger is caught (exit 1, exact FuzeFront#286 message); the restored file passes (exit 0). Not done here, and why: promoting gate-required-check-triggers itself into the branch ruleset's required set needs ruleset-write access this session was not asked to exercise, and is a separate governance decision (which checks are required) from the workflow-level fix #286 asked for. Filed as a note for @izzywdev rather than actioned. Claude-Session: https://claude.ai/code/session_013tMciHkPE8To7V67CsgKKc Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📋 Description
The Trivy check has been failing or going neutral on every PR with:
With no complete baseline to diff against, code scanning reports pre-existing findings as "new alerts" — a red check that no code change can clear. It is currently red on #813, #814 and #816, none of which touch anything it scans.
This is the "master fails CI on Trivy every time" problem. Nothing here weakens the scan.
🔄 Type of Change
🔧 Implementation Details
Two separate causes. Both are fixed here.
1. The real one — a 6-minute job sharing a tool identity with 25-second ones
GitHub creates one check run per SARIF tool, aggregating every configuration that reports under that name. Trivy writes
tool.driver.name = "Trivy"into every SARIF it produces, so all three uploads landed in a single check:ci.yml:security-scanharden-gate.yml:gate-dependency-scansecurity.ymltrivy-containerThe check was finalised long before the slow configuration reported. Observed again on #816: the Trivy check completed at
18:16:31while Container Security Scan was still running.Fix:
security.ymlretags its SARIF before upload, so the container scan gets its own check run:A 6-minute job can no longer race 25-second ones. Nothing stops being scanned — those findings simply report under Trivy Container.
2. The one an earlier fix introduced — a baseline entry with nothing producing it
Removing
ci.yml's upload in #647 did not fix the warning. It only changed which configuration goes missing — the warning previously named harden-gate's config, and now namesci.yml:security-scan. Master's code-scanning baseline still holds the analysis that step produced, and nothing re-registers it.That entry can't be aged out from the repo, and deleting it needs code-scanning admin scope:
So the only in-repo fix is to produce the configuration again. The upload is restored with no explicit
category, reproducing the exact analysis key the baseline expects.ref/shaare left toupload-sarif's own detection rather than hand-rolled, per the warning already standing inharden-gate.yml.Net result
Tool Trivy now holds exactly the two fast filesystem configurations, which finish within seconds of each other, and both are registered on master and on PRs. The slow container scan reports separately as Trivy Container.
🧪 Testing
yaml.safe_load)jqretag verified on a sample SARIF →tool.driver.namereadsTrivy Containersecurity-events: writeconfirmed present on both uploading jobscategory, which is what makes the analysis keyci.yml:security-scanDeliberately unchanged: severity filters,
.trivyignore,ignore-unfixed, andexit-code. Nothing is excluded from scanning and no finding is suppressed. This changes only which check a finding is reported under, and whether the PR diff has a baseline to compare against. The same set of findings is uploaded before and after.The failure being fixed is the opposite of a real signal: it reports findings that already exist on master as if the PR introduced them. That is what trains people to ignore the check.
Correcting the record
ci.ymlcarried a comment asserting the duplicate upload was the problem and that removing it was the fix. That was my change, and it was wrong — it moved the symptom rather than removing it. The comment is replaced with what the evidence actually shows, marked as the third pass over that block so the next person doesn't re-derive the disproven explanation.