Skip to content

fix(ci): stop the Trivy check going red on a missing SARIF configuration - #818

Merged
izzywdev merged 1 commit into
masterfrom
claude/fix-trivy-sarif-baseline
Aug 27, 2026
Merged

fix(ci): stop the Trivy check going red on a missing SARIF configuration#818
izzywdev merged 1 commit into
masterfrom
claude/fix-trivy-sarif-baseline

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

📋 Description

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

  • 🐛 Bug fix (non-breaking change which fixes an issue)

🔧 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:

Configuration Kind Duration
ci.yml:security-scan filesystem ~23s
harden-gate.yml:gate-dependency-scan filesystem ~25s
security.yml trivy-container container — builds 2 images first ~6 min

The check was finalised long before the slow configuration reported. Observed again on #816: the Trivy check completed at 18:16:31 while Container Security Scan was still running.

Fix: security.yml retags its SARIF before upload, so the container scan gets its own check run:

- name: Retag SARIF tool name so the container scan gets its own check
  run: jq '.runs[].tool.driver.name = "Trivy Container"' trivy-results.sarif > retagged.sarif

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 names ci.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:

$ gh api "repos/izzywdev/FuzeFront/code-scanning/analyses?ref=refs/heads/master&tool_name=Trivy"
{"message":"Resource not accessible by integration","status":"403"}

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 left to upload-sarif's own detection rather than hand-rolled, per the warning already standing in harden-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

  • Both workflows parse (yaml.safe_load)
  • jq retag verified on a sample SARIF → tool.driver.name reads Trivy Container
  • Retag step guards on the SARIF existing, so a scan that produced nothing can't fail the job
  • security-events: write confirmed present on both uploading jobs
  • Recovered the pre-feat(ci): add gate-toolchain — enforce the Node 24 / React 19 floor #647 step definition from git history to confirm it carried no category, which is what makes the analysis key ci.yml:security-scan

⚠️ On "is this weakening CI?" — no

Deliberately unchanged: severity filters, .trivyignore, ignore-unfixed, and exit-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.yml carried 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.

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
@github-actions
github-actions Bot requested a review from izzywdev as a code owner August 26, 2026 18:23
@github-actions github-actions Bot added the auto-merge Enable squash auto-merge once CI passes label Aug 26, 2026
@izzywdev izzywdev closed this Aug 26, 2026
@izzywdev izzywdev reopened this Aug 26, 2026
@github-actions
github-actions Bot enabled auto-merge (squash) August 26, 2026 18:55
@github-advanced-security

Copy link
Copy Markdown

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:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@izzywdev
izzywdev merged commit e8a8260 into master Aug 27, 2026
59 checks passed
@izzywdev
izzywdev deleted the claude/fix-trivy-sarif-baseline branch August 27, 2026 04:26
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-merge Enable squash auto-merge once CI passes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants