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

coderabbitaiBot 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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe 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✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck 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.

@coderabbitaicoderabbitaiBot 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-kellamand 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 mainJun 18, 2026
7 checks passed
@brendan-kellam
brendan-kellam deleted the brendan/de-llm-vuln-triage branch June 18, 2026 00:11
@github-actionsgithub-actionsBot mentioned this pull request Jun 18, 2026
Sign up for freeto 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

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
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-kellambrendan-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

coderabbitaiBot 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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe 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✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck 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.

@coderabbitaicoderabbitaiBot 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-kellamand 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 mainJun 18, 2026
7 checks passed
@brendan-kellam
brendan-kellam deleted the brendan/de-llm-vuln-triage branch June 18, 2026 00:11
@github-actionsgithub-actionsBot mentioned this pull request Jun 18, 2026
Sign up for freeto 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

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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-kellambrendan-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

coderabbitaiBot 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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe 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✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck 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.

@coderabbitaicoderabbitaiBot 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-kellamand 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 mainJun 18, 2026
7 checks passed
@brendan-kellam
brendan-kellam deleted the brendan/de-llm-vuln-triage branch June 18, 2026 00:11
@github-actionsgithub-actionsBot mentioned this pull request Jun 18, 2026
Sign up for freeto 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

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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-kellambrendan-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

coderabbitaiBot 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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe 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✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck 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.

@coderabbitaicoderabbitaiBot 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-kellamand 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 mainJun 18, 2026
7 checks passed
@brendan-kellam
brendan-kellam deleted the brendan/de-llm-vuln-triage branch June 18, 2026 00:11
@github-actionsgithub-actionsBot mentioned this pull request Jun 18, 2026
Sign up for freeto 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

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
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-kellambrendan-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

coderabbitaiBot 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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe 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✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck 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.

@coderabbitaicoderabbitaiBot 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-kellamand 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 mainJun 18, 2026
7 checks passed
@brendan-kellam
brendan-kellam deleted the brendan/de-llm-vuln-triage branch June 18, 2026 00:11
@github-actionsgithub-actionsBot mentioned this pull request Jun 18, 2026
Sign up for freeto 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

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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-kellambrendan-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

coderabbitaiBot 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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe 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✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck 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.

@coderabbitaicoderabbitaiBot 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-kellamand 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 mainJun 18, 2026
7 checks passed
@brendan-kellam
brendan-kellam deleted the brendan/de-llm-vuln-triage branch June 18, 2026 00:11
@github-actionsgithub-actionsBot mentioned this pull request Jun 18, 2026
Sign up for freeto 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

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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-kellambrendan-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

coderabbitaiBot 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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe 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✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck 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.

@coderabbitaicoderabbitaiBot 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-kellamand 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 mainJun 18, 2026
7 checks passed
@brendan-kellam
brendan-kellam deleted the brendan/de-llm-vuln-triage branch June 18, 2026 00:11
@github-actionsgithub-actionsBot mentioned this pull request Jun 18, 2026
Sign up for freeto 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

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
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-kellambrendan-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

coderabbitaiBot 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 nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe 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✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck 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.

@coderabbitaicoderabbitaiBot 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-kellamand 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 mainJun 18, 2026
7 checks passed
@brendan-kellam
brendan-kellam deleted the brendan/de-llm-vuln-triage branch June 18, 2026 00:11
@github-actionsgithub-actionsBot mentioned this pull request Jun 18, 2026
Sign up for freeto 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

@brendan-kellam