Skip to content

Commit d323a6b

Browse files
committed
Add node-cve plugin for CVE triage
Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
1 parent 8ec829d commit d323a6b

9 files changed

Lines changed: 1074 additions & 1 deletion

File tree

.claude-plugin/marketplace.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,12 @@
240240
"category": "debugging",
241241
"keywords": ["nodes", "health", "kubernetes", "diagnostics"]
242242
},
243+
{
244+
"name": "node-cve",
245+
"source": "./plugins/node-cve",
246+
"description": "CVE triage for OpenShift Node team components",
247+
"version": "0.0.1"
248+
},
243249
{
244250
"name": "bigquery",
245251
"source": "./plugins/bigquery",

docs/index.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
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 but not exploitable, Present but not reachable, Unaffected, 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. If the downstream fork or branch does not exist, the CVE is classified as Uncertain and analysis is skipped for that version.
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 | Summary Group |
119+
|---------------|---------|---------------|
120+
| Reachable | Vulnerable code path is reachable from entry points with attacker-controlled input | 🔴 Reachable |
121+
| Present but not exploitable | Vulnerable function is called, but only with trusted/internal data | 🟡 Present |
122+
| Present but not reachable | Vulnerable package is a dependency but the specific vulnerable functions are not called | 🟡 Present |
123+
| Unaffected | Vulnerable package is not in the dependency tree | 🟢 Unaffected |
124+
| Uncertain | Analysis could not determine (repo too large, CVE details insufficient, etc.) | ⚠️ Uncertain |
125+
126+
Each classification includes a confidence level (high/medium/low) based on the depth of source code analysis performed. The summary output groups "Present but not exploitable" and "Present but not reachable" together since both mean no urgent action is needed. The detailed report and Jira comments preserve the specific classification.

0 commit comments

Comments
 (0)