You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: scope vulnerability triage Linear dedup by repository
The Linear search was matching issues from other repos (e.g., a
sourcebot-helm-chart finding would match an existing sourcebot issue
with the same CVE ID). Now Claude verifies the [$REPOSITORY] prefix
in issue titles before considering it a match.
Also improves step summary visibility:
- Check-alerts summary now shows individual alert details (CVE, severity,
package, link) instead of just "Open alerts found"
- Claude analysis summary includes Linear issue links and distinguishes
open/closed/new statuses
- Linear issue creation step logs issue identifiers and URLs for every
action (skip, reopen, create, fail)
- Adds linearIssueIdentifier and linearIssueUrl to structured output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
--json-schema '{"type":"object","properties":{"cves":{"type":"array","items":{"type":"object","properties":{"cveId":{"type":"string","description":"CVE ID, GHSA ID, or codeql:<rule-id>"},"severity":{"type":"string","enum":["CRITICAL","HIGH","MEDIUM","LOW"]},"source":{"type":"string","enum":["trivy","dependabot","codeql","trivy+dependabot"],"description":"Which scanner(s) reported this finding"},"title":{"type":"string","description":"Short summary for the Linear issue title"},"description":{"type":"string","description":"Markdown analysis: affected packages, direct vs transitive, remediation steps, and references"},"affectedPackage":{"type":"string"},"linearIssueExists":{"type":"boolean"},"linearIssueId":{"type":"string","description":"The Linear issue UUID if a matching issue was found, empty string otherwise"},"linearIssueClosed":{"type":"boolean","description":"True if the matching Linear issue is in a completed or canceled state"}},"required":["cveId","severity","source","title","description","affectedPackage","linearIssueExists","linearIssueId","linearIssueClosed"]}}},"required":["cves"]}'
445
+
--json-schema '{"type":"object","properties":{"cves":{"type":"array","items":{"type":"object","properties":{"cveId":{"type":"string","description":"CVE ID, GHSA ID, or codeql:<rule-id>"},"severity":{"type":"string","enum":["CRITICAL","HIGH","MEDIUM","LOW"]},"source":{"type":"string","enum":["trivy","dependabot","codeql","trivy+dependabot"],"description":"Which scanner(s) reported this finding"},"title":{"type":"string","description":"Short summary for the Linear issue title"},"description":{"type":"string","description":"Markdown analysis: affected packages, direct vs transitive, remediation steps, and references"},"affectedPackage":{"type":"string"},"linearIssueExists":{"type":"boolean"},"linearIssueId":{"type":"string","description":"The Linear issue UUID if a matching issue was found, empty string otherwise"},"linearIssueIdentifier":{"type":"string","description":"The Linear issue identifier (e.g. SOU-926) if found, empty string otherwise"},"linearIssueUrl":{"type":"string","description":"The Linear issue URL if found, empty string otherwise"},"linearIssueClosed":{"type":"boolean","description":"True if the matching Linear issue is in a completed or canceled state"}},"required":["cveId","severity","source","title","description","affectedPackage","linearIssueExists","linearIssueId","linearIssueIdentifier","linearIssueUrl","linearIssueClosed"]}}},"required":["cves"]}'
436
446
prompt: |
437
-
You are a security engineer triaging vulnerabilities and security findings for the Sourcebot Docker image.
447
+
You are a security engineer triaging vulnerabilities and security findings for the repository **${{ github.repository }}**.
438
448
You have three data sources to analyze. Each is a JSON array where every entry has a pre-computed
439
449
`id` field for deterministic deduplication:
440
450
@@ -488,12 +498,19 @@ jobs:
488
498
curl -s -X POST https://api.linear.app/graphql \
489
499
-H "Content-Type: application/json" \
490
500
-H "Authorization: $LINEAR_API_KEY" \
491
-
-d '{"query": "query { issues(filter: { team: { id: { eq: \"'$LINEAR_TEAM_ID'\" } }, title: { contains: \"<ID>\" } }) { nodes { id title state { type } } } }"}'
501
+
-d '{"query": "query { issues(filter: { team: { id: { eq: \"'$LINEAR_TEAM_ID'\" } }, title: { contains: \"<ID>\" } }) { nodes { id identifier url title state { type } } } }"}'
492
502
```
493
-
- Set `linearIssueExists` to `true` if any matching issue is found, `false` otherwise.
503
+
- **IMPORTANT: Repository scoping.** Linear issues are titled with a `[$REPOSITORY]` prefix
504
+
(e.g., `[sourcebot-dev/sourcebot] CVE-2024-1234: ...`). When checking for existing issues,
505
+
you MUST verify that the matched issue's title starts with `[${{ github.repository }}]`.
506
+
An issue for `[sourcebot-dev/sourcebot]` is NOT the same as one for `[sourcebot-dev/sourcebot-helm-chart]`.
507
+
Ignore issues whose title prefix does not match the current repository `${{ github.repository }}`.
508
+
- Set `linearIssueExists` to `true` if a matching issue scoped to this repo is found, `false` otherwise.
494
509
- If multiple issues match, prefer the one with an open state (i.e., state type is NOT `"completed"` or `"canceled"`).
495
510
Only use a closed issue if no open issue exists for that finding.
496
511
- Set `linearIssueId` to the `id` (UUID) of the selected matching issue, or `""` if none found.
512
+
- Set `linearIssueIdentifier` to the issue identifier (e.g., `SOU-926`) of the selected matching issue, or `""` if none found.
513
+
- Set `linearIssueUrl` to the `url` of the selected matching issue, or `""` if none found.
497
514
- Set `linearIssueClosed` to `true` if the selected issue's `state.type` is `"completed"` or `"canceled"`, `false` otherwise.
498
515
499
516
8. Return the structured JSON with all findings in the `cves` array.
0 commit comments