Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .claude/commands/file-dependabot-cves.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
name: file-dependabot-cves
description: Fetch Dependabot alerts, cross-reference against LCORE Jira tickets, and file tickets for gaps
---

Audit Dependabot vulnerabilities for `$repo` (default: `lightspeed-core/lightspeed-stack`) and cross-reference them against existing LCORE Jira tickets.

## Step 1: Fetch Dependabot alerts

Fetch open Dependabot alerts using:

```
gh api "repos/$repo/dependabot/alerts" --paginate --jq '.[] | select(.state == "open") | {number, state, severity: .security_vulnerability.severity, package: .security_vulnerability.package.name, ecosystem: .security_vulnerability.package.ecosystem, summary: .security_advisory.summary, cve: (.security_advisory.cve_id // "N/A"), ghsa: .security_advisory.ghsa_id, created: .created_at, fixed_version: (.security_vulnerability.first_patched_version.identifier // "N/A")}'
```
Comment on lines +12 to +14
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifiers to fenced command blocks.

Lines 12 and 61 use unlabeled fenced blocks, which triggers markdownlint MD040 and reduces readability/tooling support.

Suggested doc fix
-```
+```bash
 gh api "repos/$repo/dependabot/alerts" --paginate --jq '.[] | select(.state == "open") | {number, state, severity: .security_vulnerability.severity, package: .security_vulnerability.package.name, ecosystem: .security_vulnerability.package.ecosystem, summary: .security_advisory.summary, cve: (.security_advisory.cve_id // "N/A"), ghsa: .security_advisory.ghsa_id, created: .created_at, fixed_version: (.security_vulnerability.first_patched_version.identifier // "N/A")}'

@@
- +bash
gh api "repos/$repo/dependabot/alerts/$alert_number" --jq '{summary: .security_advisory.summary, description: .security_advisory.description, cve: (.security_advisory.cve_id // "N/A"), remediation: (.security_vulnerability.first_patched_version.identifier // "No fix available"), vulnerable_range: .security_vulnerability.vulnerable_version_range}'

Also applies to: 61-63

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 12-12: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 @.claude/commands/file-dependabot-cves.md around lines 12 - 14, The markdown
fenced code blocks containing the gh api commands (the blocks starting with the
command gh api "repos/$repo/dependabot/alerts" --paginate --jq '...' and gh api
"repos/$repo/dependabot/alerts/$alert_number" --jq '...') are missing language
identifiers; update those fenced blocks to use "bash" (i.e., replace the opening
``` with ```bash) for both occurrences so MD040 is satisfied and shell syntax
highlighting/tooling works correctly.


If `$repo` is not provided, default to `lightspeed-core/lightspeed-stack`. Deduplicate results by (CVE + package name) when a CVE is present, or (GHSA ID + package name) when CVE is null/N/A. This prevents collapsing distinct GHSA-only advisories for the same package into a single entry.

## Step 2: Present severity summary

Present a summary table with counts by severity (Critical, High, Medium, Low), then a breakdown table grouped by package: Package | Severity | CVE | Summary | Fix Version.

## Step 3: Search LCORE Jira for existing coverage

!Requires JIRA Atlassian MCP

Search LCORE Jira for existing tickets per affected package. Batch package names into OR clauses to minimize API calls:

- By summary: `project = LCORE AND (summary ~ "pkg1" OR summary ~ "pkg2" ...)`
- By CVE label: `project = LCORE AND labels in ("CVE-XXXX-XXXXX", ...)`

Fields: `summary,status,assignee,priority,labels`. Limit: 50. Paginate if needed.

## Step 4: Cross-reference and classify

Cross-reference each Dependabot alert to its LCORE ticket(s) and classify as:
- **Covered**: open/in-progress ticket exists
- **Closed**: ticket done
- **Missing**: no ticket

Present:
1. A coverage table: Vulnerability | Sev. | Dependabot # | LCORE Ticket(s) | Status | Assignee
2. A **gaps table** listing only the missing vulnerabilities with their GitHub alert title (from `security_advisory.summary`), severity, CVE, and fix version
3. Key findings: coverage ratio, unassigned high/critical items, duplicate tickets that could be consolidated

## Step 5: Verify gaps

For each gap, cross-reference in JIRA (full-text search by CVE ID) and GitHub (confirm alert is still open) to verify it is a real missing issue. Drop false positives (e.g., already-closed tickets, stale alerts).
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle GHSA-only alerts during gap verification.

Line 47 says to verify gaps via CVE full-text Jira search, but GHSA-only advisories are in scope (Line 16). This can misclassify real gaps as “not found” and lead to duplicate filings later. Add GHSA-based Jira verification when CVE is N/A.

Suggested doc fix
-For each gap, cross-reference in JIRA (full-text search by CVE ID) and GitHub (confirm alert is still open) to verify it is a real missing issue.
+For each gap, cross-reference in JIRA (full-text search by CVE ID, or GHSA ID when CVE is `N/A`) and GitHub (confirm alert is still open) to verify it is a real missing issue.
🤖 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 @.claude/commands/file-dependabot-cves.md at line 47, The guidance that tells
reviewers to "cross-reference in JIRA (full-text search by CVE ID) and GitHub"
should be extended to handle GHSA-only advisories: when the CVE is `N/A` and the
advisory has a GHSA identifier, also perform a full-text JIRA search using the
GHSA ID and confirm the GitHub alert state by GHSA ID; update the sentence that
begins "For each gap, cross-reference..." to explicitly instruct searching JIRA
by CVE or GHSA ID (use GHSA when CVE=`N/A`) and verifying GitHub alerts by GHSA
ID to avoid misclassifying GHSA-only gaps as missing.


## Step 6: Ask user which gaps to file

Ask the user:
- Whether they want to create LCORE tickets for the missing vulnerabilities
- Which severity levels to include (e.g. "only medium and above", "all", or specific ones)
- The target fix version (look up available versions from `jira_get_project_versions` for LCORE)
- The component to assign (look up available components from `jira_get_project_components` for LCORE)

## Step 7: Fetch full advisory details and draft tickets

For each vulnerability the user wants to file, fetch the full Dependabot advisory description:

```
gh api "repos/$repo/dependabot/alerts/$alert_number" --jq '{summary: .security_advisory.summary, description: .security_advisory.description, cve: (.security_advisory.cve_id // "N/A"), remediation: (.security_vulnerability.first_patched_version.identifier // "No fix available"), vulnerable_range: .security_vulnerability.vulnerable_version_range}'
```

Structure each ticket as:

| Field | Value |
|-------|-------|
| **Project** | LCORE |
| **Type** | Vulnerability |
| **Title** | The original GitHub advisory summary (from `security_advisory.summary`) |
| **Component** | As chosen by user |
| **Fix Version** | As chosen by user |
| **Labels** | The CVE ID (if available), Security |
| **Description** | The full `security_advisory.description` from Dependabot, followed by `**Remediation:** Upgrade <package> to >= <fix_version>` (or "No upstream fix available yet" if no fix exists, including the vulnerable range). |

Present all drafted tickets in a table to the user for review before creating them.

## Step 8: Find the parent CVE epic

Search for the parent epic: `project = LCORE AND issuetype = Epic AND summary ~ "CVE" AND summary ~ "lightspeed-stack" ORDER BY created DESC`. Pick the one whose fix version matches the user's chosen fix version. If ambiguous or none found, ask the user.

## Step 9: Create tickets after user confirmation

Only after the user explicitly confirms the drafts, create the tickets using `jira_create_issue` with:
- `project_key`: LCORE
- `issue_type`: Vulnerability
- `summary`: the GitHub advisory title
- `description`: as structured above
- `components`: user's chosen component
- `additional_fields`: `{"fixVersions": [{"id": "<version_id>"}], "labels": ["<CVE-ID>", "Security"], "parent": "<EPIC_KEY>"}`
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not always include <CVE-ID> in labels.

Line 91 hardcodes "<CVE-ID>" in labels, which conflicts with GHSA-only advisories and can create empty/invalid labels. Build labels conditionally: use CVE when present, otherwise GHSA.

Suggested doc fix
-- `additional_fields`: `{"fixVersions": [{"id": "<version_id>"}], "labels": ["<CVE-ID>", "Security"], "parent": "<EPIC_KEY>"}`
+- `additional_fields`: `{"fixVersions": [{"id": "<version_id>"}], "labels": ["<CVE-OR-GHSA-ID>", "Security"], "parent": "<EPIC_KEY>"}`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `additional_fields`: `{"fixVersions": [{"id": "<version_id>"}], "labels": ["<CVE-ID>", "Security"], "parent": "<EPIC_KEY>"}`
- `additional_fields`: `{"fixVersions": [{"id": "<version_id>"}], "labels": ["<CVE-OR-GHSA-ID>", "Security"], "parent": "<EPIC_KEY>"}`
🤖 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 @.claude/commands/file-dependabot-cves.md at line 91, The doc hardcodes a CVE
label in the `additional_fields` example which can be invalid for GHSA-only
advisories; update the example for `additional_fields` so `labels` is built
conditionally—include the CVE label only when a CVE identifier exists, otherwise
include the GHSA identifier (or just "Security")—and show a template that
demonstrates this conditional choice (referencing the `additional_fields` key
and the `labels` array in the example).


Omit `parent` only if the user chose to skip it.

Report back the created ticket keys and links.
Loading