CVE Analysis
Automated analysis of HUM Jira Security (CVE) tickets. For each ticket, the tool fetches vulnerability data from MITRE and NVD, compares it against the versions shipped in the Hummingbird package repository, searches for upstream and Fedora fixes, and computes whether the ticket should be closed, moved to In Progress, or flagged for manual investigation.
How It Works
1. Ticket Selection
The tool queries Jira for HUM project tickets with component Security.
Tickets can be filtered by creation period (--show-since "2 weeks"),
limited to specific keys (HUM-796 HUM-518), or scanned in bulk. Closed
tickets are skipped by default unless --include-closed is specified or
specific ticket keys are given on the command line.
Embargoed tickets (security level “Embargoed Security Issue” or embargo status field set to true) are always skipped.
2. CVE Data Collection
For each ticket the tool:
-
Extracts the CVE ID from the Jira summary field using a regex match for CVE-YYYY-NNNN patterns.
-
Fetches the CVE record from the MITRE CVE API (
cveawg.mitre.org/api/cve/<id>) and parses the CVE 5.0affectedblock, following the CVE 5.0 Product and Version Encodings specification. This includes:- Parsing
lessThanandlessThanOrEqualversion ranges - Handling
lessThan: "*"(no upper bound) andlessThan: "4.*"(end-of-series, all versions in the 4.x series) wildcards per the spec - Processing
changeslists that subdivide ranges into affected and unaffected segments - Respecting
defaultStatusat the product level - Filtering out
versionType: "git"entries that use commit hashes instead of numeric versions (these are preserved as informational data but not used for version comparison) - Detecting CNA data errors where git commit hashes are used in
version fields without
versionType: "git", including hashes wrapped in operator syntax (e.g.,< 6374ae0bcdfe...) - Parsing inline comparison operators (
< 12.3.0,>= 4.0,<= 2.5) that are not part of the CVE 5.0 schema but are widely used by CNAs in practice - Parsing compound range bands (
>= 2.0, < 2.2.26and> 1.32.3, < 1.34.6) used by some CNAs to express a closed-open range in a single version string
- Parsing
-
Fetches version ranges from the NVD API (
services.nvd.nist.gov/rest/json/cves/2.0) and merges them with the MITRE data. When MITRE has no vendor-specific data (all vendors are “n/a”), NVD ranges replace the MITRE data entirely. An NVD API key (--nvd-api-key) enables higher rate limits. NVD references tagged “Patch” or matching commit URL patterns are also extracted and used for upstream fix detection (see below). -
Looks up the Hummingbird package version by scraping the Pulp repository index at
packages.redhat.comfor the latest RPM matching the package name extracted from the ticket summary.
3. Resolution Computation
The tool compares the shipped Hummingbird version against the affected version ranges to compute a recommended resolution:
- Closed / Done-Errata: The repo version is not in any affected range, or the repo version is >= the fix version, or the repo version appears in the “not affected” list.
- In Progress / affected: The repo version falls within an affected range.
- In Progress / affected (no version data): Neither MITRE nor NVD has
affected version information. The ticket is moved to In Progress for
manual review but does not receive the
cve-needs-attentionlabel. - In Progress / needs investigation: Version data was available but
could not be compared (e.g., CVE only provides git commit hashes), or
multiple distinct products with different versioning schemes are listed
and no
cve_productoverride is configured. These cases receive thecve-needs-attentionlabel.
4. Product Mismatch Detection
The tool detects when a CVE was filed against the wrong Hummingbird
package. It compares the CVE vendor/product names against the Hummingbird
package name and upstream repo URL from the package map. For example, a CVE
for isaacs/node-tar (an npm package) filed against the tar RPM (GNU
tar) is flagged as a mismatch. This detection works even without a repo URL
by comparing normalized product names.
When a mismatch is detected, the tool checks the vendored dependency map
(vendored_deps.csv) to see if the CVE product is a vendored dependency
inside another Hummingbird SRPM. If found:
- The warning changes from “likely misfiled” to “CVE is for vendored dependency X (version in parent SRPM)”
- The vendored version is used for resolution comparison instead of the parent package version
- The upstream fix search runs against the vendored dep’s repo (from
vendored_source.csv) instead of the parent package’s repo - The output shows “Vendored version” and the correct upstream repo
When no vendored match is found:
- The computed resolution is overridden to “New / needs investigation (product mismatch)”
- The
cve-needs-attentionlabel is applied - A Jira comment is posted explaining the mismatch
5. Upstream Fix Detection
The tool uses two complementary methods to find upstream fixes:
NVD Patch References (checked first): When the NVD response includes
reference URLs tagged “Patch” or matching commit URL patterns (GitHub
/commit/, gitweb commitdiff, cgit commit/?id=), these are used
directly as confirmed upstream fixes. This skips the forge search for
that CVE, saving API calls and finding fixes that forge search might miss.
Forge Search (fallback): Using the package map
(from the rpms repo metadata/*.json files), the tool looks up the upstream repository for
each package and searches for fixes by forge type:
- GitHub: Searches PRs via the GitHub API (
/search/issues) for PRs mentioning the CVE ID. Fetches commit counts from the pulls API. - GitLab: Searches merge requests via the GitLab API on supported
instances (gitlab.com, gitlab.gnome.org, gitlab.freedesktop.org, etc.).
The
--gitlab-tokenis only sent to gitlab.com to avoid 401 errors on other instances. - cgit: Scrapes commit log pages on cgit hosts (Savannah, Sourceware,
kernel.org, busybox.net, etc.) for commits mentioning the CVE ID.
Handles URL rewrites for Savannah hosts (e.g.,
git.savannah.gnu.org/git/tocgit.git.savannah.gnu.org/cgit/).
Fix status is classified as:
upstream-fix-available: At least one merged/closed PR, committed fix, or NVD patch referenceupstream-fix-in-progress: At least one open PR with no merged fixes
6. Fedora Fix Detection
The tool checks for Fedora fixes through two channels:
- Bodhi: Queries the Fedora Bodhi API for updates matching the package
name that reference the CVE ID (in the
cveslist ornotesfield). Supports multi-page results. Classifies updates asfedora-fix-available(stable) orfedora-fix-in-progress(testing/pending). - DistGit Spec Scan: When Bodhi has no matches, fetches the Fedora DistGit spec file and scans for CVE references in patch filenames, changelog entries, and comments to detect backported fixes.
7. Fixed Build Detection
The tool automatically detects whether the current Hummingbird build fixed a CVE by checking if all CVE IDs are mentioned anywhere in the package directory (patch names, changelogs, comments in the .spec file and so on). If found, it returns the current source RPM name. Assuming that we run the analysis frequently enough, this is precise enough, otherwise it errs on the side of caution (i.e. it possibly marks a higher version as fixed even if an earlier one already carried the fix).
The detected build is shown in the output as Detected Fix: package-version-release.hum1.src.rpm.
When --resolve is specified and a fixed build is detected, the tool
automatically populates the “Fixed in Build” Jira field with the detected SRPM
name, but only if:
- The field is not already set (manual values take precedence)
- The issue is not in Closed status (respects human closure decisions)
The RPMs repository can be provided via --rpms-repo, pointing to a local
clone. This is preferable with multiple runs to avoid the git clone operation.
When not given, the repository will be (shallow) cloned into a temporary
directory.
8. Advisory Integration (with --resolve)
When a CVE is resolved as “Closed / Done-Errata”, the tool integrates with the CEE GitLab advisories repo to document the fix:
- Clone: The advisories repo (default:
releng/advisories) is shallow-cloned via a bot fork using netrc-based authentication (no tokens in process arguments or logs). - Modify: For each resolved ticket, the advisory YAML is updated:
cves.fixedentries are added, the type is changed from RHBA to RHSA, and CVE references are appended. - Batch MR: All advisory changes are accumulated as individual commits
on a single branch (
cve-analysis/batch). One merge request is created at the end of the run covering all tickets. - Review state: Tickets are transitioned to “Review” (not directly closed) and the batch MR URL is posted to each affected ticket.
- Auto-close: On subsequent runs, tickets in “Review” are checked:
if the advisory MR has been merged, the ticket is closed as
“Done-Errata”. If the MR has unresolvable rebase conflicts, a comment
with manual resolution steps is posted and the
advisory-mr-failedlabel is added.
The advisory flow is skipped when --advisories-project points to a
non-production URL, allowing safe testing without modifying Jira.
9. Jira Actions (with --resolve)
When --resolve is specified, the tool modifies Jira tickets:
- Fixed in Build: When a fixed build is detected and the field is not already set, the tool populates it with the detected SRPM name (only for non-closed issues).
- Closed / Done-Errata: Tickets where the shipped version is not affected are transitioned to Review with an advisory MR (see above). After the MR merges, they are closed as Done-Errata on the next run.
- Move to In Progress: Tickets where the shipped version is affected are transitioned to In Progress with a comment including affected version ranges, upstream fix status, and Fedora update links.
- Needs Investigation: Tickets with incomplete version data get a comment explaining why automatic resolution was not possible.
- Product Mismatch: A comment is posted explaining the mismatch and the
cve-needs-attentionlabel is applied. No transition is performed. - Label Management: Labels are applied and updated:
upstream-fix-available/upstream-fix-in-progressfedora-fix-available/fedora-fix-in-progresscve-needs-attention(applied when human review is needed; removed when resolved)- Labels are upgraded (in-progress to available) and stale labels are cleaned up on ticket closure.
Every Jira action (label add/remove, status transition, product mismatch) includes a single comment with a bold action summary heading followed by the full analysis output in a preformatted code block, giving the reader the same detail they would see on the CLI.
10. Assignee-Based Automation Control
When --resolve is active, the tool checks each ticket’s assignee. If
the assignee is not the bot account (--jira-user), the tool skips all
automated actions (comments, labels, transitions) for that ticket. A
one-time comment is posted explaining that automation is skipped. This
allows humans to take ownership of a ticket by assigning it to
themselves, preventing the bot from interfering with manual work.
Reassigning back to the bot account re-enables automation.
For testing purposes, use --skip-assignee-check to process all tickets
regardless of assignee.
11. Human Closure Protection
When the tool encounters a Closed ticket whose analysis recommends a non-Closed resolution (e.g., In Progress), it checks the Jira changelog to determine who performed the last status transition. If a human (not the bot) closed the ticket, the tool skips the transition to respect the human’s decision. This prevents the tool from reopening tickets where a fix was backported without a version bump or where a human determined the CVE does not apply.
12. Stale Closure Detection (with --include-closed)
When --include-closed is used, the tool also analyzes Closed tickets. If
the current analysis recommends a non-Closed resolution (e.g., the package
version changed and is now affected), a warning is emitted flagging the
ticket for review.
13. Continuous Operation
When --time-between-runs N is set (N > 0), the tool runs in a loop,
re-executing the full analysis every N minutes. The default is 0 (single
run). Shutdown is graceful: SIGINT/SIGTERM finishes the current cycle
before exiting.
14. Feature Flag
When --feature-flag-name is set (default: cve_analysis_enabled), the
tool checks a GitLab feature flag on the project specified
by --feature-flag-project-id (default: 73447720, i.e. redhat/hummingbird/rpms) at
the start of each cycle. If the flag is inactive, the cycle is skipped
and the tool sleeps for 60 seconds before checking again.
The check uses the --gitlab-token / GITLAB_TOKEN credential, which
must have Developer role or higher on the target project. The check is
fail-open: if GitLab is unreachable or the token lacks permissions, the
tool assumes the flag is enabled and proceeds.
Set --feature-flag-name "" to disable the check entirely.
Package Map
The package map is loaded from the rpms repo’s per-package metadata files
(metadata/<package>.json). Each file contains an upstream_repo field
pointing to the canonical upstream git repository, plus optional fields:
upstream_branch– upstream branch (for versioned packages sharing a repo)cve_product– CVE vendor/product overrideversion_transform– version transform rule
The cve_product field is an optional human-curated value that specifies
which CVE vendor/product entry maps to this package. It supports two
formats:
Vendor / Product(exact match): matches a specific vendor and product pair. Example:"F5 / NGINX Open Source"for thenginxpackage, which excludes NGINX Plus entries that use incompatible R-versioning.Vendor(vendor prefix match): matches any product whose vendor starts with the given string. Example:"Go "forgolangpackages, where the vendor varies (Go standard library,Go toolchain, etc.) and the product varies by module (net/url,os,crypto/x509).
When cve_product is set, the tool uses it for exact product matching in
both resolution computation (filtering to the correct product in
multi-product CVEs) and mismatch detection. When empty, the tool falls
back to heuristic name matching.
The rpms repo is cloned automatically at startup (or provided via
--rpms-repo). A CSV override can be passed via --package-map for
backward compatibility.
Vendored Package Map
The vendored_source.csv and vendored_deps.csv files map vendored
dependencies (Go modules, Rust crates, npm packages) inside Hummingbird
SRPMs to their upstream repositories. These are generated by the
generate_vendored_map.py script, which downloads SRPMs, extracts
vendored lock files (vendor/modules.txt, Cargo.lock,
package-lock.json), and resolves upstream repos via the crates.io, npm
registry, and Go module path conventions.
During analysis, when a CVE product mismatch is detected, the tool
searches vendored_deps.csv for the CVE product name. Go subpackages
are matched by progressively stripping path components (e.g.,
github.com/jackc/pgx/v5/pgproto3 matches github.com/jackc/pgx/v5).
When a match is found, the vendored version is used for resolution and
the upstream fix search targets the vendored dep’s repo from
vendored_source.csv. The --vendored-deps-map option can override the
default path.
Prerequisites
- Python 3.11 or later
- Jira API token (Bearer or Basic auth)
- Network access to
redhat.atlassian.net,cveawg.mitre.org,services.nvd.nist.gov,bodhi.fedoraproject.org,src.fedoraproject.org, andpackages.redhat.com - GitHub API token (optional, for upstream PR search)
- GitLab API token (optional, for gitlab.com MR search)
- CEE GitLab API token (required with
--resolve, for advisory repo)
Usage
# Basic usage with Jira token from environment
export JIRA_TOKEN=your_token
python3 -m hummingbird_tools.cve_analysis --jira-user user@example.com
# Analyze specific tickets
python3 -m hummingbird_tools.cve_analysis --jira-user user@example.com HUM-796 HUM-518
# Show only tickets from the last 2 weeks
python3 -m hummingbird_tools.cve_analysis --jira-user user@example.com --show-since "2 weeks"
# Analyze with upstream fix detection (report findings without modifying Jira)
export GITHUB_TOKEN=your_github_token
python3 -m hummingbird_tools.cve_analysis --jira-user user@example.com
# Resolve tickets and apply labels
python3 -m hummingbird_tools.cve_analysis --jira-user user@example.com --resolve
# Include closed tickets and check for stale closures
python3 -m hummingbird_tools.cve_analysis --jira-user user@example.com --include-closed
# Include closed tickets but exclude specific ones
python3 -m hummingbird_tools.cve_analysis --jira-user user@example.com \
--include-closed --exclude "HUM-555,HUM-552"
# JSON output, skip issues without CVE links
python3 -m hummingbird_tools.cve_analysis --jira-user user@example.com -o json-pretty --skip-no-cve
# Continuous mode: resolve tickets every 30 minutes
python3 -m hummingbird_tools.cve_analysis --jira-user user@example.com \
--resolve --time-between-runs 30
Configuration
| Option | Environment Variable | Description |
|---|---|---|
--jira-token |
JIRA_TOKEN |
Jira API or Bearer token |
--jira-url |
Jira base URL (default: https://redhat.atlassian.net) |
|
--jira-user |
Username for Basic auth | |
--output, -o |
Output format: human, json, json-pretty |
|
--show-since |
Filter by creation period (e.g. 2 weeks, 3 hours) |
|
--resolve |
Transition Jira tickets and apply labels | |
--skip-assignee-check |
Skip assignee validation (for testing) | |
--include-closed |
Include Closed tickets in analysis; warn on stale closures | |
--exclude |
Comma-separated ticket keys to skip (e.g. HUM-555,HUM-552) |
|
--skip-no-cve |
Omit issues that have no CVE link or ID | |
--max-results |
Max number of issues to fetch (default: 2000) | |
--github-token |
GITHUB_TOKEN |
GitHub API token for upstream PR search |
--gitlab-token |
GITLAB_TOKEN |
GitLab API token for gitlab.com MR search |
--nvd-api-key |
NVD_API_KEY |
NVD API key for higher rate limits |
--cee-gitlab-token |
CEE_GITLAB_TOKEN |
CEE GitLab token for advisory repo operations |
--advisories-project |
Advisories repo URL (default: releng/advisories) |
|
--advisories-fork |
Bot’s fork URL for advisory MR creation | |
--no-merge-request |
Skip advisory MR creation during --resolve |
|
--test-advisory |
Create advisory MR then immediately close it (for testing) | |
--package-map |
Path to CSV override; by default uses rpms repo metadata | |
--vendored-deps-map |
Path to vendored_deps.csv (auto-detected by default) |
|
--rpms-repo |
Path to RPMs git repo for fixed build detection | |
--time-between-runs |
Re-run every N minutes; 0 = single run (default) | |
--feature-flag-project-id |
GitLab project ID for feature flag lookup (default: 73447720, rpms project) |
|
--feature-flag-name |
Feature flag name to check each cycle (default: cve_analysis_enabled; empty = disabled) |
|
SENTRY_DSN |
Optional Sentry DSN for error tracking |
Managed Labels
The tool manages the following labels on Jira tickets. These are automatically applied, upgraded, and cleaned up:
| Label | Meaning |
|---|---|
upstream-fix-available |
A merged PR or committed fix exists upstream |
upstream-fix-in-progress |
An open PR exists upstream (no merged fix yet) |
fedora-fix-available |
A stable Fedora Bodhi update references this CVE |
fedora-fix-in-progress |
A testing/pending Bodhi update references this |
fedora-bz-filed |
A Fedora Bugzilla has been filed for this CVE |
cve-needs-attention |
Analysis needs human attention (see below) |
advisory-mr-failed |
Advisory MR has unresolvable rebase conflicts |
Labels are upgraded automatically (e.g., upstream-fix-in-progress is
replaced by upstream-fix-available when a fix is merged). Stale labels
are removed when tickets are closed, except fedora-bz-filed which is
preserved as an audit record. The cve-needs-attention label is removed
automatically when the warning condition no longer applies.
cve-needs-attention conditions
The cve-needs-attention label is applied when any of these conditions
are detected:
- Product mismatch: CVE vendor/product does not match the Hummingbird package (e.g. node-tar CVE filed against GNU tar)
- Multiple products: CVE lists multiple distinct products with different
versioning schemes and no
cve_productoverride is configured (e.g. NGINX Open Source + NGINX Plus) - Git-only version data: CVE version data uses commit hashes instead of
numeric versions (e.g. libsodium with
lessThan: ad3004ec...) - CNA data error: A git commit hash is used where a version number is
expected without setting
versionType: "git", including hashes embedded in operator syntax (e.g.,"version": "< 6374ae0bcdfe..."). The warning includes a link to the CVE 5.0 source control versions spec - Malformed version field: The version field contains syntax that could
not be parsed (e.g., compound operator+hash ranges like
>= hash1, < hash2) - CVE fetch failure: the MITRE CVE API request failed
- No repo version: the Hummingbird package was not found in the Pulp repository (package name mismatch or missing SRPM)
- Stale closure: ticket is Closed in Jira but current analysis recommends a different resolution
Human override workflow
When a human wants to take over a ticket from the bot:
-
Assign the ticket to yourself – the bot skips all automation on tickets not assigned to the bot account. Reassign to the bot to re-enable automation.
-
Set “Fixed in Build” – if you know the fix is in a specific SRPM, set the “Fixed in Build” field to the SRPM name (e.g.
libarchive-3.8.7-1.hum1.src.rpm). The bot will use this to create the advisory MR and close the ticket, bypassing its own analysis.
Migration note: The cve-analysis-okay label is deprecated and no
longer suppresses automation. Existing tickets with this label will be
re-processed by the bot on its next run. To keep the bot from touching a
specific ticket, reassign it to yourself before the next run. The
cve-analysis-okay label can then be removed manually.
Output
Human-Readable
Project: HUM Component: Security
HUM-796 CVE-2026-2673 openssl: buffer overflow [hummingbird-1]
Open since: 7 days (Mar 24 2026)
Labels resolution: upstream-fix-available
OpenSSL / OpenSSL:
Affected versions: 3.5.0 < 3.5.6
Fixed in: 3.5.6
Hummingbird repo (latest): 3.5.5 / openssl-3.5.5-1.hum1.src.rpm
Repo: https://github.com/openssl/openssl
CVE-2026-2673: upstream-fix-available (3 PRs)
[CLOSED, 3 commits] Fix group tuple handling in DEFAULT expansion (3.5)
https://github.com/openssl/openssl/pull/30110
Fedora update: FEDORA-2026-abc123 openssl-3.5.6-1.fc44 (stable, security)
https://bodhi.fedoraproject.org/updates/FEDORA-2026-abc123
Jira current: In Progress / (none)
Jira resolution: In Progress / affected (repo 3.5.5 is in affected range 3.5.0 < 3.5.6)
JSON
Each issue includes: key, summary, labels, open_since, cve_ids,
cves (with version and resolution data), jira_current (status/resolution),
computed_resolution, and upstream (with PR/MR search results, Bodhi
updates, and Fedora version data).
Development
See the main README for development workflows.
make hummingbird-cve-analysis/setup # Install dependencies
make check # Lint code (ruff)
make test # Run unit tests
License
This project is licensed under the GNU General Public License v3.0 or later - see the LICENSE file for details.