Skip to content

Commit 01c5966

Browse files
eshulman2claude
andcommitted
Add CVE processing tools for Jira vulnerability management
Main script (dup_cve.py): - Query unprocessed CVE Vulnerabilities from OCPBUGS - Create Epic per CVE/component in OSASINFRA - Create Task per version in OSASINFRA (linked to Epic) - Create ON_QA Bug in OCPBUGS for versions without CVEs - Link Tasks to CVEs (is caused by) and add processed label - Link Tasks to created Bugs (is related to) - Create dependency chain between versions (older depends on newer) - Idempotent: reuses existing issues, skips processed CVEs Utility scripts: - manage_task_cves.py: Manage CVEs linked to a task - update fields (release notes, patch links), transition status, close task - inspect_issues.py: Show issue status and links - reset_cves.py: Remove processed labels, optionally remove links (depends on, duplicates, blocks), and reassign issues Library (lib/): - jira_client.py: Jira API client with field caching, link type lookup, remote links, and issue link management - jira_formatter.py: Field formatting utilities Configuration: - config.yaml: Component mappings and label settings - Supports dry-run mode for safe testing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8c10ef8 commit 01c5966

File tree

11 files changed

+2950
-0
lines changed

11 files changed

+2950
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66

77
# ignore cloud credentials
88
/bot/cloud-credentials.json
9+
10+
__pycache__/

cve-jira-processing/README.md

Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
# CVE Jira Processing
2+
3+
Tools for processing CVE Vulnerability issues in Jira. Queries Jira for unprocessed CVEs, creates tracking structures, and establishes dependency chains across versions.
4+
5+
The script is **idempotent** - it can be run multiple times safely without creating duplicate issues.
6+
7+
## Setup
8+
9+
1. Install dependencies:
10+
```bash
11+
pip install -r requirements.txt
12+
```
13+
14+
2. Set environment variables:
15+
```bash
16+
export JIRA_API_TOKEN="your-api-token"
17+
export JIRA_SERVER="https://issues.redhat.com" # optional, this is the default
18+
```
19+
20+
## Scripts
21+
22+
| Script | Description |
23+
|--------|-------------|
24+
| `dup_cve.py` | Main script for CVE processing |
25+
| `manage_task_cves.py` | Manage CVEs linked to a task (update fields, close, set release notes) |
26+
| `inspect_issues.py` | Inspect issues - show status and links |
27+
| `reset_cves.py` | Remove processed labels to allow reprocessing |
28+
29+
## Usage
30+
31+
### dup_cve.py - Main Processing Script
32+
33+
```bash
34+
# Dry run - see what would be done without making changes
35+
python dup_cve.py --dry-run
36+
37+
# Process CVEs for real
38+
python dup_cve.py
39+
40+
# Process only a specific CVE
41+
python dup_cve.py --cve CVE-2024-1234
42+
43+
# Verbose output for debugging
44+
python dup_cve.py --dry-run -v
45+
46+
# Use a custom config file
47+
python dup_cve.py --config /path/to/config.yaml
48+
```
49+
50+
### inspect_issues.py - Inspect Issues
51+
52+
```bash
53+
# Inspect specific issues
54+
python inspect_issues.py OCPBUGS-12345 OSASINFRA-67890
55+
56+
# Inspect issues from a file
57+
python inspect_issues.py -f issues.txt
58+
59+
# Combine both
60+
python inspect_issues.py OCPBUGS-12345 -f more_issues.txt
61+
```
62+
63+
### manage_task_cves.py - Manage CVEs Linked to a Task
64+
65+
```bash
66+
# See what CVEs are linked to a task
67+
python manage_task_cves.py OSASINFRA-12345 --dry-run
68+
69+
# Close all linked CVEs with defaults (status=Closed, resolution=Done)
70+
python manage_task_cves.py OSASINFRA-12345
71+
72+
# Transition to a different status
73+
python manage_task_cves.py OSASINFRA-12345 --status ON_QA
74+
75+
# Close with custom comment and resolution
76+
python manage_task_cves.py OSASINFRA-12345 --comment "Fixed in OCPBUGS-99999" --resolution "Fixed"
77+
78+
# Set release note fields when closing (using defaults: type=CVE, status=Proposed)
79+
python manage_task_cves.py OSASINFRA-12345 \
80+
--release-note-text "This CVE was addressed upstream." \
81+
--release-note-type \
82+
--release-note-status
83+
84+
# Set release note fields with custom values
85+
python manage_task_cves.py OSASINFRA-12345 \
86+
--release-note-text "This CVE was addressed upstream." \
87+
--release-note-type "Bug Fix" \
88+
--release-note-status "Done"
89+
90+
# Update release notes without transitioning (no status change)
91+
python manage_task_cves.py OSASINFRA-12345 --no-transition \
92+
--release-note-text "This CVE was addressed upstream." \
93+
--release-note-type \
94+
--release-note-status
95+
96+
# Add a patch link to CVEs
97+
python manage_task_cves.py OSASINFRA-12345 \
98+
--patch-url "https://github.com/org/repo/pull/123" \
99+
--patch-title "Fix for CVE-2024-1234"
100+
101+
# Transition CVEs to POST and task to POST
102+
python manage_task_cves.py OSASINFRA-12345 --status POST --task-status POST
103+
104+
# Close CVEs and the parent task
105+
python manage_task_cves.py OSASINFRA-12345 --close-task
106+
107+
# Close CVEs and task with patch link on both
108+
python manage_task_cves.py OSASINFRA-12345 --close-task \
109+
--patch-url "https://github.com/org/repo/pull/123"
110+
111+
# Close task with custom resolution
112+
python manage_task_cves.py OSASINFRA-12345 \
113+
--task-status Closed --task-resolution "Won't Fix"
114+
```
115+
116+
### reset_cves.py - Reset Processed Labels
117+
118+
```bash
119+
# Dry run - see what would be reset
120+
python reset_cves.py --dry-run
121+
122+
# Actually remove labels
123+
python reset_cves.py
124+
125+
# Reset only a specific CVE
126+
python reset_cves.py --cve CVE-2024-1234
127+
128+
# Reset issues from a file
129+
python reset_cves.py -f issues.txt
130+
131+
# Also remove dependency and duplicate links
132+
python reset_cves.py -f issues.txt --remove-links
133+
134+
# Transition issues back to ASSIGNED status
135+
python reset_cves.py -f issues.txt --reassign
136+
137+
# Full reset: remove label, links, and reassign
138+
python reset_cves.py -f issues.txt --remove-links --reassign
139+
```
140+
141+
## Processing Flow
142+
143+
```
144+
┌─────────────────────────────────────────────────────────────┐
145+
│ 1. Query unprocessed CVEs │
146+
│ - Status: New or Assigned │
147+
│ - No processed label │
148+
│ - Matching configured downstream components │
149+
└─────────────────────────────────────────────────────────────┘
150+
151+
┌─────────────────────────────────────────────────────────────┐
152+
│ 2. Group by {component}:{cve_id} │
153+
└─────────────────────────────────────────────────────────────┘
154+
155+
┌─────────────────────────────────────────────────────────────┐
156+
│ 3. For each CVE group: │
157+
│ a. Find/create Epic in OSASINFRA │
158+
│ b. Query ALL CVEs for this CVE ID (version detection) │
159+
│ c. Calculate range: min(CVE versions) → max(available) │
160+
└─────────────────────────────────────────────────────────────┘
161+
162+
┌─────────────────────────────────────────────────────────────┐
163+
│ 4. For each version in range: │
164+
│ ├─ Create Task in OSASINFRA (with Epic Link) │
165+
│ ├─ If CVEs exist: │
166+
│ │ ├─ Link Task to CVEs (is caused by) │
167+
│ │ ├─ Set Target Backport Versions = Affects Version/s │
168+
│ │ └─ Add processed label to all CVEs │
169+
│ └─ If NO CVEs: │
170+
│ ├─ Create ON_QA Bug in OCPBUGS │
171+
│ └─ Link Task → is related to → Bug │
172+
└─────────────────────────────────────────────────────────────┘
173+
174+
┌─────────────────────────────────────────────────────────────┐
175+
│ 5. Create dependency chain (older depends on newer): │
176+
│ 4.12 → depends on → 4.13 → depends on → 4.14 │
177+
└─────────────────────────────────────────────────────────────┘
178+
```
179+
180+
## JQL Queries Used
181+
182+
### 1. Initial Query - Find Unprocessed CVEs
183+
184+
```sql
185+
project = OCPBUGS AND type = Vulnerability
186+
AND ("Downstream Component Name" ~ "comp1" OR "Downstream Component Name" ~ "comp2" ...)
187+
AND labels != "{cve_processed_label}"
188+
AND status IN (New, Assigned)
189+
AND "CVE ID" ~ "{cve_filter}" -- only if --cve flag provided
190+
```
191+
192+
### 2. Secondary Query - Find All Related CVEs
193+
194+
```sql
195+
project = OCPBUGS AND type = Vulnerability
196+
AND "CVE ID" ~ "{cve_id}"
197+
AND ("Downstream Component Name" ~ "comp1" OR ...)
198+
AND (status != Closed OR resolution IN (Duplicate, "Won't Do", "Not a Bug"))
199+
```
200+
201+
### 3. Find Existing Epic
202+
203+
```sql
204+
project = OSASINFRA AND type = Epic
205+
AND summary ~ "\"{cve_id} - {component}\""
206+
```
207+
208+
### 4. Find Existing Task
209+
210+
```sql
211+
project = OSASINFRA AND type = Task
212+
AND summary ~ "\"{cve_id} - {component} - {version}\""
213+
```
214+
215+
### 5. Find Existing Bug
216+
217+
```sql
218+
project = OCPBUGS AND type = Bug
219+
AND summary ~ "\"{cve_id} - {component} - {version}\""
220+
```
221+
222+
## Issue Structure Created
223+
224+
```
225+
OSASINFRA:
226+
├── Epic: CVE-2024-1234 - openstack-cinder
227+
│ ├── Task: CVE-2024-1234 - openstack-cinder - 4.12 (Epic Link)
228+
│ │ └── is caused by: CVE (Vulnerability) for 4.12
229+
│ ├── Task: CVE-2024-1234 - openstack-cinder - 4.13 (Epic Link)
230+
│ │ └── is caused by: CVE (Vulnerability) for 4.13
231+
│ ├── Task: CVE-2024-1234 - openstack-cinder - 4.14 (Epic Link)
232+
│ │ └── is related to: ON_QA Bug (no CVE reported)
233+
│ └── Task: CVE-2024-1234 - openstack-cinder - 4.15 (Epic Link)
234+
│ └── is related to: ON_QA Bug (no CVE reported)
235+
236+
OCPBUGS (only created where no CVE exists):
237+
├── Bug: CVE-2024-1234 - openstack-cinder - 4.14 (ON_QA)
238+
└── Bug: CVE-2024-1234 - openstack-cinder - 4.15 (ON_QA)
239+
240+
Dependency Chain (older depends on newer):
241+
CVE-4.12 → depends on → CVE-4.13 → depends on → Bug-4.14 → depends on → Bug-4.15
242+
```
243+
244+
## Link Types Used
245+
246+
| Source | Link Type | Target | Description |
247+
|--------|-----------|--------|-------------|
248+
| Task | Epic Link (field) | Epic | Tasks belong to the Epic |
249+
| Task | is related to | Bug (ON_QA) | Task linked to created bug |
250+
| Task | is caused by | CVE | Task is caused by the CVE |
251+
| Older issue | depends on | Newer issue | Dependency chain |
252+
253+
## Fields Set on Created Issues
254+
255+
### Epics (in OSASINFRA)
256+
257+
| Field | Value |
258+
|-------|-------|
259+
| Project | OSASINFRA |
260+
| Issue Type | Epic |
261+
| Summary | `{CVE ID} - {component}` |
262+
| Epic Name | `{CVE ID} - {component}` |
263+
| Security Level | Red Hat Employee |
264+
| Assignee | User running the script |
265+
| Description | `Grouping epic for bugs related to {CVE ID} - {component}` |
266+
267+
### Tasks (in OSASINFRA)
268+
269+
| Field | Value |
270+
|-------|-------|
271+
| Project | OSASINFRA |
272+
| Issue Type | Task |
273+
| Summary | `{CVE ID} - {component} - {version}` |
274+
| Security Level | Red Hat Employee |
275+
| Assignee | User running the script |
276+
| Epic Link | Link to parent Epic |
277+
278+
### ON_QA Bugs (in OCPBUGS)
279+
280+
| Field | Value |
281+
|-------|-------|
282+
| Project | OCPBUGS |
283+
| Issue Type | Bug |
284+
| Summary | `{CVE ID} - {component} - {version}` |
285+
| Component/s | Inherited from source CVE issues |
286+
| Target Version | `{version}.z` (e.g., 4.14.z) |
287+
| Security Level | Red Hat Employee |
288+
| Assignee | User running the script |
289+
| Status | Transitioned to ON_QA |
290+
291+
## Version Range Logic
292+
293+
- **Minimum version**: Lowest version with a reported CVE
294+
- **Maximum version**: Latest available target version in Jira
295+
- All versions in between get a Task in OSASINFRA
296+
- Versions without a CVE get an ON_QA Bug in OCPBUGS for QA verification
297+
298+
## Idempotency
299+
300+
The script can be run multiple times safely:
301+
302+
- **Existing Epics** are reused (searched by summary)
303+
- **Existing Tasks** are reused (searched by summary)
304+
- **Existing Bugs** are reused (searched by summary)
305+
- **Already-processed CVEs** are identified by the processed label and skipped
306+
307+
## Files
308+
309+
| File | Description |
310+
|------|-------------|
311+
| `dup_cve.py` | Main script for CVE processing |
312+
| `manage_task_cves.py` | Utility to manage CVEs linked to a task |
313+
| `inspect_issues.py` | Utility to inspect issue status and links |
314+
| `reset_cves.py` | Utility to remove processed labels |
315+
| `lib/jira_client.py` | Jira API client wrapper |
316+
| `lib/jira_formatter.py` | Field formatting utilities for Jira API requests |
317+
| `config.yaml` | Configuration file (component mappings, labels) |
318+
319+
## Configuration
320+
321+
The `config.yaml` file contains:
322+
323+
- **cve_processed_label**: Label applied to processed CVE issues
324+
- **repo_to_component**: Mapping of downstream repository names to component names
325+
326+
The script queries for Vulnerabilities matching the downstream components defined in `repo_to_component`.
327+
328+
To add support for new components, add entries to the `repo_to_component` section:
329+
330+
```yaml
331+
repo_to_component:
332+
openshift4/ose-new-component-rhel9: openshift/new-component
333+
```
334+
335+
## Example Output
336+
337+
```
338+
2025-01-15 10:30:00 - Loaded config from config.yaml
339+
2025-01-15 10:30:00 - Configured components: ['openshift4/ose-cloud-provider-openstack-rhel9', ...]
340+
2025-01-15 10:30:01 - Found 50 numeric target versions
341+
2025-01-15 10:30:01 - Querying Jira for Vulnerabilities...
342+
2025-01-15 10:30:05 - Found 7 unprocessed Vulnerabilities
343+
2025-01-15 10:30:05 - Found 2 CVE groups
344+
345+
2025-01-15 10:30:05 - Processing CVE group: openstack-cinder:CVE-2024-1234
346+
2025-01-15 10:30:05 - CVE: CVE-2024-1234, Component: openstack-cinder
347+
2025-01-15 10:30:05 - Found CVEs in versions: ['4.12', '4.13']
348+
2025-01-15 10:30:05 - Processing versions: ['4.12', '4.13', '4.14', '4.15', '4.16']
349+
2025-01-15 10:30:06 - Created Epic: OSASINFRA-99999
350+
2025-01-15 10:30:07 - Version 4.12:
351+
2025-01-15 10:30:07 - Created task: OSASINFRA-100000
352+
2025-01-15 10:30:07 - 2 CVEs (1 new)
353+
2025-01-15 10:30:07 - OCPBUGS-11111 (already processed)
354+
2025-01-15 10:30:08 - Linked: OCPBUGS-22222
355+
2025-01-15 10:30:09 - Version 4.13:
356+
2025-01-15 10:30:09 - Created task: OSASINFRA-100001
357+
2025-01-15 10:30:09 - 1 CVEs (1 new)
358+
2025-01-15 10:30:09 - Linked: OCPBUGS-33333
359+
2025-01-15 10:30:10 - Version 4.14:
360+
2025-01-15 10:30:10 - Created task: OSASINFRA-100002
361+
2025-01-15 10:30:10 - No CVEs, creating ON_QA bug
362+
2025-01-15 10:30:11 - Created bug: OCPBUGS-100003
363+
2025-01-15 10:30:11 - Transitioned OCPBUGS-100003 to ON_QA
364+
...
365+
366+
======================================================================
367+
SUMMARY (DRY RUN - no changes made)
368+
======================================================================
369+
370+
TOTALS
371+
----------------------------------------
372+
Epics: 2 (1 existing, 1 to create)
373+
Tasks: 10 (3 existing, 7 to create)
374+
Bugs: 6 (0 existing, 6 to create)
375+
CVEs: 5 to link
376+
377+
DETAILS BY CVE GROUP
378+
----------------------------------------
379+
[CVE-2024-1234] openstack-cinder
380+
Epic: OSASINFRA-99999
381+
Tasks (5): OSASINFRA-100000, OSASINFRA-100001, ... OSASINFRA-100004
382+
Bugs (3): OCPBUGS-100003, OCPBUGS-100004, OCPBUGS-100005
383+
CVEs (2): OCPBUGS-11111, OCPBUGS-22222
384+
385+
======================================================================
386+
```

0 commit comments

Comments
 (0)