Skip to content

chore(ci): remove LLM summary generation from vulnerability triage#1334

Merged
brendan-kellam merged 5 commits into
mainfrom
brendan/de-llm-vuln-triage
Jun 18, 2026
Merged

chore(ci): remove LLM summary generation from vulnerability triage#1334
brendan-kellam merged 5 commits into
mainfrom
brendan/de-llm-vuln-triage

Conversation

@brendan-kellam

@brendan-kellam brendan-kellam commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Reworks .github/workflows/vulnerability-triage.yml so it no longer generates any LLM summary. The Claude analysis step is replaced with deterministic jq/curl scripting that reproduces everything Claude was doing:

  • Build findings — a single jq program builds the cves list from the three normalized scan files:
    • Dedup by the pre-computed id (a CVE/GHSA in both Trivy and Dependabot merges into one trivy+dependabot entry).
    • CodeQL alerts grouped by rule id into one entry listing every location.
    • Severities normalized to uppercase; titles and descriptions templated from raw scan fields.
  • Match existing Linear issues — resolves the team UUID / CVE label / Triage state / API-key owner once, then searches Linear per finding, applies the [<repository>] title-prefix scoping, and prefers an open issue over a closed one.

The downstream Write findings summary and Create Linear issues steps are unchanged in logic — they read findings.json (same JSON shape the old structured_output produced) instead of the Claude step output, and the create step reuses the metadata resolved by the match step.

Also:

  • Removes the ANTHROPIC_API_KEY secret from the reusable workflow_call (no callers pass it).
  • Renames the job Claude Analysis & Linear TriageLinear Triage.

Testing

Validated the jq build program against sample data (Trivy↔Dependabot id collision merges, Dependabot-only retained, multi-location CodeQL grouped into one), the Linear match-selection logic (open repo-scoped preferred, other repos ignored, closed-only falls into the reopen path, no-match → exists:false), and the empty-findings edge case. YAML parses cleanly.

Note: no CHANGELOG entry — this is an internal CI/security-automation change, not user-facing.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Updated the vulnerability triage workflow to build structured findings deterministically from scanner outputs, with improved deduplication/grouping.
    • Added matching against existing issue metadata and enhanced the findings summary with total/new/existing-open/existing-closed counts.
    • Refactored issue creation to reuse results from the earlier matching step.
    • Updated workflow controls/job naming and streamlined workflow inputs by removing an unneeded secret for reusable calls.

Replace the Claude analysis step in the vulnerability-triage workflow with
deterministic jq/curl scripting. Findings are now built directly from the
normalized Trivy, Dependabot, and CodeQL scan files (dedup by pre-computed
id, CodeQL grouped by rule, templated titles/descriptions), and existing
Linear issues are matched via GraphQL. No LLM is used anywhere.

Drops the ANTHROPIC_API_KEY secret from the reusable workflow (no callers
pass it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

@brendan-kellam your pull request is missing a changelog!

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 17b89d5d-0be3-45b7-b8ee-04f134e1b2fd

📥 Commits

Reviewing files that changed from the base of the PR and between 03f9893 and 6e221ca.

📒 Files selected for processing (1)
  • .github/workflows/vulnerability-triage.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/vulnerability-triage.yml

Walkthrough

The vulnerability triage GitHub Actions workflow removes its dependency on Claude/Anthropic by replacing the AI analysis step with a deterministic jq pipeline. The workflow interface drops the ANTHROPIC_API_KEY secret, the triage job is renamed, alert inputs are deduplicated and normalized into structured findings JSON, and the Linear issue creation step now consumes pre-resolved metadata from the preceding match step.

Changes

Vulnerability Triage Workflow Refactor

Layer / File(s) Summary
Workflow interface and job naming changes
.github/workflows/vulnerability-triage.yml
Workflow trigger added for push to main; workflow_dispatch.force_analysis description updated to reference triage; ANTHROPIC_API_KEY removed from workflow_call secrets; triage job renamed from "Claude Analysis & Linear Triage" to "Linear Triage".
Deterministic findings build, match, and summary pipeline
.github/workflows/vulnerability-triage.yml
"Build findings" step replaces Claude analysis: jq transforms and deduplicates Trivy/Dependabot alerts by id and groups CodeQL alerts by rule id into findings-base.json/findings.json. "Match existing Linear issues" populates per-finding Linear metadata via GraphQL. "Write findings summary" replaces "Write Claude analysis summary" with match-status-based counts.
Create Linear issues env wiring
.github/workflows/vulnerability-triage.yml
Step environment updated to consume team_uuid, label_id, state_id, and viewer_id from steps.match outputs, removing reliance on Claude output and LINEAR_TEAM_ID resolution.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'chore(ci): remove LLM summary generation from vulnerability triage' directly and clearly summarizes the main change: removing Claude-based LLM analysis from the vulnerability triage workflow and replacing it with deterministic scripting.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch brendan/de-llm-vuln-triage

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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
.github/workflows/vulnerability-triage.yml (1)

574-588: ⚡ Quick win

Consider validating the Linear API response before processing.

If the GraphQL request fails (network error, rate limit, server error), $RESPONSE won't contain .data.issues.nodes, and the null-safe jq will produce {linearIssueExists: false, ...}. This would cause the workflow to create a duplicate issue when one actually exists but the lookup failed.

♻️ Proposed fix to check for API errors
             PAYLOAD=$(jq -n --arg query "$SEARCH_QUERY" --argjson vars "$VARS" '{query: $query, variables: $vars}')
-            RESPONSE=$(curl -s -X POST https://api.linear.app/graphql \
+            HTTP_CODE=$(curl -s -o /tmp/linear-search.json -w "%{http_code}" -X POST https://api.linear.app/graphql \
               -H "Content-Type: application/json" \
               -H "Authorization: $LINEAR_API_KEY" \
               -d "$PAYLOAD")
+            RESPONSE=$(cat /tmp/linear-search.json)
+
+            if [ "$HTTP_CODE" != "200" ] || echo "$RESPONSE" | jq -e '.errors' >/dev/null 2>&1; then
+              echo "::warning::Linear API error for $CVE_ID (HTTP $HTTP_CODE). Assuming no existing issue."
+            fi
 
             SELECTED=$(echo "$RESPONSE" | jq --arg prefix "[$REPOSITORY]" '
🤖 Prompt for 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.

In @.github/workflows/vulnerability-triage.yml around lines 574 - 588, Add
validation of the Linear API response in the vulnerability-triage.yml workflow
before processing the jq filter on $RESPONSE. Check if the GraphQL response
contains errors (using jq to detect .errors field) or if the expected data
structure is missing, and fail the workflow step explicitly when the API call
fails rather than silently treating a failed request as "issue not found". This
prevents the workflow from incorrectly creating duplicate issues when the API
lookup fails due to network errors, rate limits, or server errors.
🤖 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.

Nitpick comments:
In @.github/workflows/vulnerability-triage.yml:
- Around line 574-588: Add validation of the Linear API response in the
vulnerability-triage.yml workflow before processing the jq filter on $RESPONSE.
Check if the GraphQL response contains errors (using jq to detect .errors field)
or if the expected data structure is missing, and fail the workflow step
explicitly when the API call fails rather than silently treating a failed
request as "issue not found". This prevents the workflow from incorrectly
creating duplicate issues when the API lookup fails due to network errors, rate
limits, or server errors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 69cf1786-392c-4626-bc42-bd0de18717ec

📥 Commits

Reviewing files that changed from the base of the PR and between ed74594 and 70c3952.

📒 Files selected for processing (1)
  • .github/workflows/vulnerability-triage.yml

brendan-kellam and others added 4 commits June 17, 2026 16:16
Trivy can report the same CVE multiple times (across lockfiles/targets or
when a CVE affects several packages). The previous build mapped over every
Trivy entry, so duplicate ids produced duplicate findings and therefore
duplicate Linear issues. Group Trivy and Dependabot by id so each unique id
yields exactly one finding, collecting all affected packages into it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ates

The Linear search bound the team UUID as a `String!` GraphQL variable into
`team.id.eq`, which expects `ID`. That variable-type mismatch made every
search return null data, so no finding ever matched an existing issue and the
job re-filed every CVE on each run. Drop the team filter (repo-prefix title
scoping is the authoritative filter anyway) and warn when a search errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@brendan-kellam brendan-kellam merged commit 18d41ba into main Jun 18, 2026
7 checks passed
@brendan-kellam brendan-kellam deleted the brendan/de-llm-vuln-triage branch June 18, 2026 00:11
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