Skip to content

Commit caa04ce

Browse files
committed
Add node-cve plugin for daily Node team CVE triage
Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
1 parent d4833ba commit caa04ce

10 files changed

Lines changed: 1124 additions & 0 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@
181181
"description": "Kubernetes and OpenShift node health monitoring and diagnostics",
182182
"version": "0.0.3"
183183
},
184+
{
185+
"name": "node-cve",
186+
"source": "./plugins/node-cve",
187+
"description": "CVE triage for OpenShift Node team components",
188+
"version": "0.0.1"
189+
},
184190
{
185191
"name": "bigquery",
186192
"source": "./plugins/bigquery",

PLUGINS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ This document lists all available Claude Code plugins and their commands in the
2020
- [Marketplace Ops](#marketplace-ops-plugin)
2121
- [Must Gather](#must-gather-plugin)
2222
- [Node](#node-plugin)
23+
- [Node Cve](#node-cve-plugin)
2324
- [Node Tuning](#node-tuning-plugin)
2425
- [Olm](#olm-plugin)
2526
- [Olm Team](#olm-team-plugin)
@@ -259,6 +260,15 @@ Kubernetes and OpenShift node health monitoring and diagnostics
259260

260261
See [plugins/node/README.md](plugins/node/README.md) for detailed documentation.
261262

263+
### Node Cve Plugin
264+
265+
CVE triage for OpenShift Node team components
266+
267+
**Commands:**
268+
- **`/node-cve:triage` `[--component <name>] [--notify-jira] [--notify-slack] [--days N]`** - Triage all open CVEs for OpenShift Node team components with reachability analysis
269+
270+
See [plugins/node-cve/README.md](plugins/node-cve/README.md) for detailed documentation.
271+
262272
### Node Tuning Plugin
263273

264274
Automatically create and apply tuned profile

docs/data.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,6 +1693,39 @@
16931693
"skills": [],
16941694
"version": "0.0.3"
16951695
},
1696+
{
1697+
"commands": [
1698+
{
1699+
"argument_hint": "[--component <name>] [--notify-jira] [--notify-slack] [--days N]",
1700+
"description": "Triage all open CVEs for OpenShift Node team components with reachability analysis",
1701+
"example": "",
1702+
"name": "triage",
1703+
"synopsis": "/node-cve:triage [--component \"Node / CRI-O\"] [--notify-jira] [--notify-slack] [--days 7]"
1704+
}
1705+
],
1706+
"description": "CVE triage for OpenShift Node team components",
1707+
"has_readme": true,
1708+
"hooks": [],
1709+
"name": "node-cve",
1710+
"skills": [
1711+
{
1712+
"description": "Analyze CVE reachability against downstream repository forks at version-specific release branches",
1713+
"id": "analyze-cve-repos",
1714+
"name": "analyze-cve-repos"
1715+
},
1716+
{
1717+
"description": "Query and deduplicate open CVE vulnerability issues from OCPBUGS for Node team components",
1718+
"id": "query-open-cves",
1719+
"name": "query-open-cves"
1720+
},
1721+
{
1722+
"description": "Generate triage reports and post findings to Jira and Slack",
1723+
"id": "report-findings",
1724+
"name": "report-findings"
1725+
}
1726+
],
1727+
"version": "0.0.1"
1728+
},
16961729
{
16971730
"commands": [
16981731
{
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "node-cve",
3+
"description": "CVE triage for OpenShift Node team components",
4+
"version": "0.0.1",
5+
"author": {
6+
"name": "github.com/openshift-eng"
7+
}
8+
}

plugins/node-cve/OWNERS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
approvers:
2+
- saschagrunert
3+
reviewers:
4+
- saschagrunert

plugins/node-cve/README.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Node CVE Plugin
2+
3+
CVE triage for OpenShift Node team components. Queries open vulnerability issues from OCPBUGS, runs reachability analysis against affected repositories, and reports findings to Jira and Slack.
4+
5+
## Command
6+
7+
### `/node-cve:triage [--component <name>] [--notify-jira] [--notify-slack] [--days N]`
8+
9+
Triage all open CVEs for Node team components with automated reachability analysis.
10+
11+
**Example:**
12+
```text
13+
/node-cve:triage --notify-jira --notify-slack
14+
```
15+
16+
**What it does:**
17+
18+
1. Queries OCPBUGS for open Vulnerability issues across all Node team components (CRI-O, Kubelet, MCO, etc.)
19+
2. Deduplicates by CVE ID (each CVE has multiple version trackers)
20+
3. Clones affected repositories at all version-specific release branches and analyzes source code for reachability
21+
4. Classifies each CVE: REACHABLE, PRESENT_NOT_EXPLOITABLE, PRESENT_NOT_REACHABLE, NOT_AFFECTED, or UNCERTAIN
22+
5. Generates a triage report with confidence levels and recommended actions
23+
6. Posts analysis comments to Jira tracker issues (with `--notify-jira`)
24+
7. Sends a threaded summary to Slack (with `--notify-slack`)
25+
26+
**Arguments:**
27+
- `--component <name>`: Filter to a specific component (e.g., "Node / CRI-O")
28+
- `--notify-jira`: Post analysis results as comments on Jira tracker issues (also enables cross-run caching)
29+
- `--notify-slack`: Send summary to Slack (API token for threading, or webhook for simple messages)
30+
- `--days N`: Only include CVEs updated in the last N days (default: all open)
31+
32+
**Output:**
33+
- Summary table printed to stdout
34+
- Full report at `.work/node-cve/triage-YYYY-MM-DD/report.md`
35+
- Structured data at `.work/node-cve/triage-YYYY-MM-DD/cves.json`
36+
- Per-CVE analysis files in `.work/node-cve/triage-YYYY-MM-DD/`
37+
38+
## Prerequisites
39+
40+
```bash
41+
# Jira CLI
42+
# See https://github.com/ankitpokhrel/jira-cli
43+
44+
# git (for cloning repos)
45+
# curl (for --notify-slack)
46+
```
47+
48+
**Environment variables:**
49+
- `JIRA_API_TOKEN` - Jira API token (required)
50+
- `JIRA_USERNAME` - Jira username/email (required)
51+
- `SLACK_API_TOKEN` - Slack bot token (preferred for `--notify-slack`, enables threaded messages)
52+
- `SLACK_CHANNEL` - Slack channel ID (required with `SLACK_API_TOKEN`). Default: `GK6BJJ1J5` (`#team-node`)
53+
- `SLACK_WEBHOOK` - Slack incoming webhook URL (alternative for `--notify-slack`, no threading)
54+
55+
## Headless Execution
56+
57+
Run as a scheduled job using the ai-helpers container:
58+
59+
```bash
60+
podman run -it \
61+
-e CLAUDE_CODE_USE_VERTEX=1 \
62+
-e ANTHROPIC_VERTEX_PROJECT_ID=your-project \
63+
-e JIRA_API_TOKEN=... \
64+
-e JIRA_USERNAME=... \
65+
-e SLACK_API_TOKEN=xoxb-... \
66+
-e SLACK_CHANNEL=GK6BJJ1J5 \
67+
-v ~/.config/gcloud:/home/claude/.config/gcloud:ro \
68+
ai-helpers --print "/node-cve:triage --notify-jira --notify-slack"
69+
```
70+
71+
### OpenShift CronJob
72+
73+
```yaml
74+
apiVersion: batch/v1
75+
kind: CronJob
76+
metadata:
77+
name: node-cve-triage
78+
namespace: node-team
79+
spec:
80+
schedule: "3 8 * * 1-5"
81+
jobTemplate:
82+
spec:
83+
template:
84+
spec:
85+
containers:
86+
- name: triage
87+
image: ai-helpers:latest
88+
args: ["--print", "/node-cve:triage --notify-jira --notify-slack"]
89+
envFrom:
90+
- secretRef:
91+
name: cve-triage-secrets
92+
restartPolicy: OnFailure
93+
```
94+
95+
## Node Team Components
96+
97+
The plugin covers all OCPBUGS components owned by the Node team. Analysis targets downstream forks at version-specific release branches. When a downstream fork or branch does not exist, it falls back to the upstream repo. This two-step fallback is necessary because some downstream forks (e.g., openshift/cri-o) do not yet have branches for all OCP versions.
98+
99+
| Component | Downstream Fork | Upstream Repo | Branch Pattern | Language |
100+
|-----------|----------------|--------------|---------------|----------|
101+
| Node / CRI-O | openshift/cri-o | cri-o/cri-o | `release-1.X` | Go |
102+
| Node / Kubelet | openshift/kubernetes | kubernetes/kubernetes | `release-1.X` | Go |
103+
| Node / CPU manager | openshift/kubernetes | kubernetes/kubernetes | `release-1.X` | Go |
104+
| Node / Device Manage | openshift/kubernetes | kubernetes/kubernetes | `release-1.X` | Go |
105+
| Node / Memory manager | openshift/kubernetes | kubernetes/kubernetes | `release-1.X` | Go |
106+
| Node / Numa aware Scheduling | openshift/kubernetes | kubernetes/kubernetes | `release-1.X` | Go |
107+
| Node / Pod resource API | openshift/kubernetes | kubernetes/kubernetes | `release-1.X` | Go |
108+
| Node / Topology manager | openshift/kubernetes | kubernetes/kubernetes | `release-1.X` | Go |
109+
| Driver Toolkit | openshift/driver-toolkit | - | `release-4.Y` | Go |
110+
| Machine Config Operator | openshift/machine-config-operator | - | `release-4.Y` | Go |
111+
112+
Additional repos detected via `pscomponent:` labels: openshift/google-cadvisor (Go), openshift/conmon (C), openshift/conmon-rs (Rust + Go), openshift/cri-tools / kubernetes-sigs/cri-tools (Go).
113+
114+
For OCP 4.Y, the K8s/CRI-O version is `1.(Y+13)` (e.g., OCP 4.18 -> K8s/CRI-O 1.31). This mapping will change for OCP 5.x.
115+
116+
## Reachability Classification
117+
118+
| Classification | Meaning |
119+
|---------------|---------|
120+
| REACHABLE | Vulnerable code path is reachable from entry points with attacker-controlled input |
121+
| PRESENT_NOT_EXPLOITABLE | Vulnerable function is called, but only with trusted/internal data |
122+
| PRESENT_NOT_REACHABLE | Vulnerable package is a dependency but the specific vulnerable functions are not called |
123+
| NOT_AFFECTED | Vulnerable package is not in the dependency tree |
124+
| UNCERTAIN | Analysis could not determine (repo too large, CVE details insufficient, etc.) |
125+
126+
Each classification includes a confidence level (HIGH/MEDIUM/LOW) based on the depth of source code analysis performed.

0 commit comments

Comments
 (0)