Hummingbird Data Flow

Overview of all data sources, what is stored where, and how data moves between systems.


Data sources

Source What it provides
Jira REST API CVE tracker ticket fields (status, timestamps, labels, custom fields)
Jira whiteboard (customfield_10841) Per-ticket timestamp cache written back by the analysis tool
Red Hat Pulp (packages.redhat.com) SRPM/RPM publish timestamps for Hummingbird repos
Hummingbird container catalog API Image rebuild history (when a package first appeared in a rebuilt image)
Red Hat CSAF VEX feed (security.access.redhat.com) Advisory fix/not-affected status per CVE
OSIDB (osidb.prodsec.redhat.com) Subpackage-level affectedness data
NVD / CVE list CVE publish dates, product/version data
GitHub / GitLab Upstream fix commit / PR / release dates
Fedora updates Fedora update availability timestamps
Konflux SNS/SQS events Pipeline run, snapshot, release, MR, push events

PostgreSQL databases

There are two Postgres databases.

1. hummingbird-status — Konflux pipeline events

Fed by SNS/SQS events via the hummingbird-status ingestor.

Table Primary key What is stored
gitlab_pushes (sha, repo, ref) Git push events — sha, branch, commit list
components name Konflux component definitions and git context
pipelineruns name Build/test PLR outcomes, status, start/completion times
snapshots name Multi-component snapshots, source PLR, sha
releases name Release outcomes, images, LLM analysis text
gitlab_merge_requests (project, iid) Current MR state, merge commit sha
gitlab_mr_versions (project, iid, sha) Per-commit history of each MR head

2. hummingbird-dashboard — CVE lifecycle + dashboard overlays

Table Primary key / unique What is stored
cve_ticket_events (ticket_key, event_type) One row per lifecycle milestone per ticket. occurred_at = timestamp; metadata = JSONB (see below). The source of all R-Time computations.
cve_analysis_log id Each analysis tool run: timestamp, ticket count, log output
cve_ticket_claims ticket_key Claim/lock for deduplicating concurrent analysis runs
dashboard_settings key Runtime flags: auto-rerun enabled, analysis enabled, etc.
auto_rerun_log id History of automatic retrigger attempts
blocked_error_patterns id Regex patterns that suppress auto-rerun
blocked_snapshots snapshot_name Manually blocked snapshots
analysis_log / analysis_costs id LLM failure analysis runs and token costs
blocked_push_builds / push_build_rerun_log id Push build blocking and retry history
package_lifecycle (package, event_type) Package-scoped lifecycle milestones (e.g. rpm_first_published). Distinct from cve_ticket_events — one row per package/milestone, not per ticket.

cve_ticket_events lifecycle milestone event_type values

These are the canonical names after the HUM-5918 migration:

event_type Meaning
cve_published CVE published date (NVD / CVE list)
hum_ticket_created HUM Jira ticket creation date
hum_ticket_closed HUM Jira ticket resolution date
upstream_fix_merged Upstream fix commit / release merged
fedora_update_available Fedora update containing the fix became available
rpm_fix_published_to_pulp Fix RPM published to Hummingbird Pulp repo
image_rebuilt_on_quay Hummingbird container image rebuilt with the fix
vex_resolved Red Hat CSAF VEX advisory confirmed the resolution (HUM-5843)

rpm_fix_published_to_pulp and image_rebuilt_on_quay are mutable — they are updated when a newer delivery event supersedes the previous one. All other event types are write-once: once set, occurred_at is never overwritten.

cve_ticket_events.metadata JSONB fields

Each row carries a metadata blob that reflects the ticket’s state at the time of the most recent analysis run:

Field Source Description
computed_resolution analysis tool Hummingbird’s computed fix status
jira_status Jira status field Current Jira issue status
labels Jira labels field All labels on the ticket
fixed_in_build Jira customfield_10578 SRPM set manually in the “Fixed in Build” field
detected_fixed_build Pulp / SRPM detection SRPM filename auto-detected from Pulp repodata
vex_status Red Hat VEX feed fixed / known_not_affected / …
vex_match_state reconciliation logic matched / pending / mismatch
vex_resolved VEX reconciliation Timestamp when VEX first agreed with Jira resolution

Jira whiteboard (customfield_10841)

The CVE analysis tool uses the Jira whiteboard field as a per-ticket timestamp cache. This is being phased out in favour of Postgres as the durable store (HUM-5917), but is still the source for a subset of fields.

The whiteboard holds compact JSON. The relevant sub-key is cve_cycle:

cve_cycle key Meaning Mutable?
cve_published CVE publish date No — write-once
jira_created HUM ticket creation date No — write-once
jira_closed HUM ticket close date No — disabled (255-char limit)
upstream_fix Upstream fix timestamp No — write-once
fedora_fix Fedora update timestamp No — write-once
hb_rpm_fix RPM published to Pulp Yes — re-evaluated each run
hb_image_fix Image rebuilt on Quay Yes — re-evaluated each run

The whiteboard is read and written only by the CVE analysis tool. The dashboard never reads it directly; its authoritative source is always cve_ticket_events.


Jira fields read by the CVE analysis tool

On each run the analysis tool fetches every open HUM CVE tracker ticket and reads the following fields from the Jira REST API:

Jira field / custom field Purpose
summary Ticket title / package detection
status, resolution, resolutiondate Ticket lifecycle state
created Jira ticket creation date → hum_ticket_created
description, comment CVE ID extraction, fix evidence
labels cve-next-release, fix-in-progress, etc.
security Embargo level
assignee Ticket owner
customfield_10578 (Fixed in Build) Manually set SRPM identifying the fix build
customfield_10841 (Whiteboard) Cached cve_cycle timestamps (read + write)
customfield_10667 (CVE ID) Structured CVE identifiers
customfield_10860 (Embargo Status) Embargo flag
customfield_10020 (Sprint) Sprint membership
customfield_10014 (Epic Link) Parent epic

Data flow

┌─────────────────────────────────────────────────────────────────┐
│  External data sources                                          │
│                                                                 │
│  Jira REST API ─────────────────────────────────────┐           │
│  NVD / CVE list ────────────────────────────────────┤           │
│  GitHub / GitLab (upstream fix commits) ────────────┤           │
│  Fedora updates ────────────────────────────────────┤           │
│  Red Hat Pulp (RPM publish times) ─────────────────►│           │
│  Hummingbird catalog API (image rebuild times) ─────┤           │
│  Red Hat CSAF VEX feed ─────────────────────────────┤           │
│  OSIDB (subpackage affectedness) ───────────────────┘           │
└──────────────────────────────┬──────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│  CVE analysis tool (cron, hummingbird-cve-analysis)              │
│                                                                  │
│  • Reads Jira ticket fields + whiteboard cache                   │
│  • Resolves fix SRPM from Pulp repodata                          │
│  • Resolves image rebuild timestamp from catalog API             │
│  • Checks upstream PR/release dates (GitHub/GitLab)              │
│  • Fetches CVE publish date (NVD/CVE list)                       │
│  • Reconciles VEX status (CSAF feed)                             │
│  • Checks subpackage affectedness (OSIDB)                        │
│                                                                  │
│  Writes back to:                                                 │
│  ├── Jira whiteboard (cve_cycle timestamp cache)                 │
│  ├── Jira labels / Fixed-in-Build field                          │
│  ├── Jira comments                                               │
│  └── dashboard DB → cve_ticket_events (one row per milestone)    │
│                      cve_analysis_log (run record)               │
└──────────────────────────────┬───────────────────────────────────┘
           ┌───────────────────┴───────────────────┐
           │                                       │
           ▼                                       ▼
┌──────────────────────────┐      ┌───────────────────────────────┐
│  Jira whiteboard         │      │  dashboard DB                 │
│  (per-ticket JSON cache) │      │  cve_ticket_events table      │
│  cve_cycle timestamps    │      │  one row per (ticket,         │
│  ← being phased out      │      │    event_type) milestone      │
│    (HUM-5917)            │      └───────────────┬───────────────┘
└──────────────────────────┘                      │
                               ┌──────────────────────────────────┐
                               │  hummingbird-dashboard API       │
                               │                                  │
                               │  Pivots cve_ticket_events rows   │
                               │  into per-ticket dicts, computes:│
                               │  • entry-level R-Time fields     │
                               │    (HUM-5920)                    │
                               │  • duration legs inside stages   │
                               │    (HUM-5921)                    │
                               │                                  │
                               │  Serves JSON + Jinja templates   │
                               └──────────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│  Konflux SNS/SQS event stream                           │
│                                                         │
│  GitLab pushes, PipelineRuns, Snapshots, Releases, MRs  │
│  → hummingbird-status ingestor                          │
│  → hummingbird-status DB (pipeline/release tables)      │
│  → hummingbird-dashboard API (build/release views)      │
└─────────────────────────────────────────────────────────┘

API field names

The dashboard API exposes these computed fields per R-Time entry:

Entry-level fields

API field Meaning
cve_published_at Start of R-Time (CVE publish date, or upstream fix if later)
fix_delivered_at Image delivery date (RPM fallback)
cve_to_delivery_hours Total R-Time: cve_published_atfix_delivered_at
cve_to_hum_created_hours Filing lag: CVE publish → HUM ticket opened
fix_before_cve_published True when RPM/image shipped before CVE was published
hum_ticket_open True for unresolved pre-built cases (R-Time still accumulating)
deferred_to_next_release True for cve-next-release tickets
display_duration_hours Display-safe duration (elapsed so far for open tickets)

Duration legs (stages dict)

API field Interval
cve_published_to_hum_created CVE publish → HUM ticket opened
cve_published_to_upstream_fix CVE publish → upstream fix merged
hum_created_to_upstream_fix HUM ticket → upstream fix merged
upstream_fix_to_fedora_update Upstream fix → Fedora update available
fedora_update_to_rpm_fix_published Fedora update → fix RPM in Pulp
upstream_fix_to_rpm_fix_published Upstream fix → fix RPM in Pulp
hum_created_to_rpm_fix_published HUM ticket → fix RPM in Pulp
rpm_fix_published_to_image_rebuilt Fix RPM in Pulp → image rebuilt on Quay
image_rebuilt_to_hum_closed Image rebuild → HUM ticket closed

Aggregate stats

API field Meaning
avg_hum_created_to_rpm_fix_hours Mean HUM ticket → RPM fix (excludes pre-built)
avg_rpm_fix_to_image_rebuilt_hours Mean RPM publish → image rebuild

Package lifecycle data

rpm_first_published is the earliest timestamp at which any SRPM for a given package appeared in the Hummingbird Pulp repo. It is package-scoped — one row per package — as opposed to cve_ticket_events which is ticket-scoped.

Collection

scripts/collect_rpm_first_published --prod --rpms-repo /path/to/rpms

Flow:

  1. Loads the package list from rpms_repo.load_package_map_from_metadata().
  2. For each package: calls pulp.fetch_earliest_srpm_time(), which browses packages.redhat.com/.../source/Packages/{letter}/, parses the HTML listing already used by the analysis tool, and returns the earliest upload timestamp across all SRPMs for that package.
  3. POSTs all results in one request to /api/cve-import (same endpoint used for cve_ticket_events sync). The dashboard upserts with COALESCE(LEAST(existing, incoming), existing, incoming) — re-runs only update occurred_at if the incoming timestamp is earlier, and NULLs are never stored over a real value.

Surfaced in dump_lifecycle

scripts/dump_lifecycle --prod HUM-1234

After fetching ticket milestones from cve_ticket_events, the script resolves the package name from those rows and makes a second call to /api/cve-export?section=package_lifecycle to fetch rpm_first_published for that package. It is shown at the bottom of the text output and under rpm_first_published in the JSON output.