Repository navigation
feat(correlation): evidence-based correlation engine - #2693
Conversation
Reviewer's GuideThis PR establishes an evidence-first correlation foundation: it persists extractor-produced component/vulnerability links, resolves them into precedence-based verdicts, exposes those results through a new SBOM correlation endpoint, documents the architecture, and wires in initial service and endpoint tests. Sequence diagram for SBOM correlation verdict retrievalsequenceDiagram
participant Client
participant API as CorrelationEndpoint
participant Service as CorrelationService
participant DB as ReadOnlyDatabase
Client->>API: GET /v3/correlation/sbom/{id}
API->>DB: Query correlation_evidence for sbom_id
DB-->>Service: Evidence rows
Service->>DB: Load nodes, checksums, advisories, vulnerabilities
DB-->>Service: Correlation metadata
Service->>Service: correlate_sbom(sbom_id, connection)
Service-->>API: CorrelationResult with verdicts and evidence
API-->>Client: 200 JSON response
Entity relationship diagram for correlation evidence storageerDiagram
SBOM ||--o{ CORRELATION_EVIDENCE : contains
ADVISORY ||--o{ CORRELATION_EVIDENCE : provides
CORRELATION_EVIDENCE {
uuid id PK
uuid sbom_id FK
text node_id
uuid advisory_id FK
text vulnerability_id
assertion_status status
match_dimension match_dimension
float confidence
text extractor
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
171fa8c to
4b41bde
Compare
1aef529 to
dce6eb7
Compare
1139747 to
ffa813a
Compare
f683eba to
c6deadc
Compare
5c3ce95 to
2654e41
Compare
| @@ -0,0 +1,3 @@ | |||
| DROP TABLE remediation_product_identifier_assertion; | |||
There was a problem hiding this comment.
there is now a m0002390_create_crypto_remediation
There was a problem hiding this comment.
Fixed in feadf62. The PR migrations are now numbered sequentially from m0002410 through m0002590, after upstream's crypto remediation and base PURL name index migrations. Updated the SQL include paths, tests, and documentation references as well. Formatting and compilation checks for the migration and correlation test targets passed.
| @@ -0,0 +1,63 @@ | |||
| use sea_orm_migration::prelude::*; | |||
There was a problem hiding this comment.
there is now a m0002390_create_crypto_remediation
There was a problem hiding this comment.
Fixed in feadf62: the correlation evidence migration is now m0002410_create_correlation_evidence, and the remaining PR migrations follow sequentially through m0002590. Upstream's existing migration names are preserved.
| #[post("/v3/upload/from-url")] | ||
| #[allow(clippy::too_many_arguments)] | ||
| /// Download a document from a URL and ingest it with auto-detected format. | ||
| pub async fn upload_document_from_url( |
There was a problem hiding this comment.
I tihnk auth runs after download ... require_permission() is only called once format has been detected from fetched bytes so any authed user can make server issue requests
There was a problem hiding this comment.
Authentication already runs in the /api middleware before the handler, but you are right that the format-specific authorization check happened after downloading. Fixed in 2803f79 by adding Require before the handler runs. It requires at least one of create.sbom, create.advisory, create.weakness, or create.exploit before any outbound request. After downloading and detecting the format, we still require that format's specific permission before ingestion. Regression tests verify that anonymous users and users with no upload permission (including unrelated create permissions) trigger zero outbound requests, and that a different upload permission does not authorize ingestion. All 12 upload tests pass.
| @@ -0,0 +1,75 @@ | |||
| use migration::{ | |||
There was a problem hiding this comment.
I think this migration is 'one way' ...
rh-jfuller
left a comment
There was a problem hiding this comment.
I found all the sql to have no kind of injection paths ;) which is good ... I provided a few comments, otherwise this PR is good enough to go into main ... I would rather we get it in before it grows any bigger !
77983fb to
126612e
Compare
…ion UI Consolidates the following changes in their original order: - feat(correlation): add correlation engine foundation with evidence table and verdict API - docs(correlation): add README with API examples - feat(correlation): add digest-based correlation extractor - feat(correlation): add identifier query, product identifier ingestion, and URL-based advisory ingest - refactor(correlation): unify query endpoint with verdict pipeline - feat(correlation): show unmatched SBOM components and populate PURLs/CPEs - fix(ui): use origin as OIDC redirect_uri for deep-link support - feat(correlation): add product identifier extractor, document upload, and advisory UI - feat(correlation): add matched_value to evidence and show all component types - fix(correlation): adapt csaf hash/identifier extraction to csaf-rs 0.5 types - chore(deps): switch garage-door from local path to 0.2.1 - chore(correlation): add the S18 and S19 scenario data - refactor(correlation): merge unmatched component type columns into single Identifiers column - refactor(correlation): isolate identifier types behind an Extractor trait - refactor(correlation): use named result types for extractor matches - chore: ignore trunk lock file and xtask SBOM output - refactor(correlation): switch to usize - chore(ui): include correlation UI in precommit clippy and check - refactor(correlation): require explicit identifier kind for queries - feat(ui): support uploading multiple files via drag and drop - feat(ingestor): accept compressed documents from the UI and URLs Assisted-by: Codex
…eams Consolidates the following changes in their original order: - feat(correlation): add CPE extractor with version range matching - feat(correlation): show verdict counts in the SBOM list - docs(correlation): document the matching approach of the extractors - feat(correlation): implement PURL-based matching in PurlExtractor - chore(deps): update garage-door to 0.3.0 - feat(correlation): scope RPM PURL matches by release stream - refactor(correlation): derive Red Hat's implied affected ranges in correlation - fix(cpe): drop a CPE language which isn't a language tag - feat(csaf): ingest the "recommended" product status - feat(correlation): keep one evidence record per status - feat(correlation): match SUSE PURLs by codestream - fix(csaf): store version ranges as stated - feat(correlation): evaluate CSAF vls ranges by PURL type - fix(csaf): resolve products defined outside of branches - fix: replace deprecated fetch_update with try_update - chore(ui): replace deprecated Sass @import with @use Assisted-by: Codex
The correlation details page already shows an alert when results are outdated, so the per-SBOM label in the list is just noise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While a refresh covering the outdated results is queued or running, there's nothing the user can do but wait. Show an info alert pointing to the refresh progress instead of the warning asking for a refresh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add an endpoint listing all factors a match confidence can be made of, built from the same constants and rules the extractors use, and a UI page explaining how they combine and how confidence ranks evidence. Confidence breakdowns link to it, and it lives in a new "Documentation" nav group, together with the API documentation link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…groups Assisted-by: Codex
List importers with their state, progress and last runs, enable, run, delete and create them, and show an importer's run reports and edit its configuration as JSON. Importers are listed under "Administration", which is now shown without correlation as well. Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the switch and buttons in importer rows with a kebab menu in the table's action cell, and show the same menu as an "Actions" toggle in the importer page header, as PatternFly recommends. Confirm deleting an importer with a new, shared confirmation dialog. Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add GET /api/v4/importer, which accepts the common query and pagination parameters and returns paginated results ordered by name, keeping pages stable while importers run. Deprecate GET /api/v3/importer, which returns all importers as an array, and use the new listing in the load tests. Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fetch pages of importers from the paginated listing, with the total. Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summarize an importer in compact cards, reusing those of the advisory page, and add a "Last run" tab with the timing, results and messages of its most recent run. Show the messages of runs as a paginated table. Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Like the API command, --devmode creates the storage directory and applies database migrations, so the importer can be started on its own against a fresh database. Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without any processed item, the rate is zero and the estimated remaining time infinite, which overflowed computing the estimated completion and panicked when reading such an importer. Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expand past runs in the reports to review their details and messages, like the most recent run, and summarize them by result and message counts. Show the remaining time and estimated completion of running importers. Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assisted-by: Codex
Assisted-by: Codex
Assisted-by: Codex
Report how long each ingestion source, the correlation extraction and the dump took, including the extraction throughput. Migrate the dump generator from log to tracing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assisted-by: Claude Code
Without a working directory, the database, storage and importer checkouts went to /tmp, which may be a size-limited tmpfs. The working directory can now also be set with GENERATE_DUMP_WORKING_DIR. Without one, use a temporary directory in Cargo's target directory, and fall back to the system's temporary directory only when not running through Cargo. Keep the shared PostgreSQL installation. Also limit the storage archive to the storage directory, instead of the whole working directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assisted-by: Claude Code
2803f79 to
26020b4
Compare
Depends on #2775 (utoipa 6 upgrade). Merge #2775 first.
Summary
An evidence-based correlation engine (ADR 00023): ingestion stores what documents state,
extractors turn those statements into evidence (component × vulnerability, with match
dimension, confidence and provenance), and verdicts are resolved from the evidence.
This covers stages 1–3 of the ADR roadmap, plus what real-world data required on top.
Correlation (
modules/correlation)correlation_evidencetable, extraction worker, and verdict resolution (Fixed > NotAffected >Affected > UnderInvestigation).
mainline minors, EUS/AUS/E4S as separate products), SUSE codestreams;
CPEs, ancestors, and RPM PURLs), so statements of other products/streams don't leak.
fixed_is_first_fixed(Red Hatstates
fixedonly for the fixing build; enabled for Red Hat by default).GET /v3/correlation/sbom/{id},POST /v3/correlation/verdict-counts,GET /v3/correlation/query,GET /v3/correlation/advisory/{id}/statement,CRUD on
/v3/correlation/option.Ingestion
recommended,first_fixed,first_affected,last_affected,under_investigation), version ranges as stated, product context ofstatements, products defined outside of branches.
rule). The fundamental SBOM, PURL and vulnerability APIs still report those "affected"
statuses: as a bridge until they use the correlation verdicts, they read the views
purl_status_effective/version_range_effective(m0002560), which add them at query timefor publishers enabling
fixed_is_first_fixed(nothing inferred is stored).UI (
ui/, Yew/PatternFly)SBOM list with verdict counts, correlation results with evidence and product context, advisory
viewer with stored statements, management of correlation options.
Other
m0002380…m0002560. Advisories ingested beforem0002510/m0002540need to bere-ingested for product contexts and the additional CSAF statuses.
deny.tomlexceptions for the correlation UI (wasm, not shipped with the server).Policy changes — please confirm:
progenitor-clientonly (viatrustify-client);ctron/trustify-clients(trustify-clientwith derivedPartialEq, untilfeat: derive PartialEq on all generated API types rh-jfuller/trustify-clients#10 is released);
bincode,paste,proc-macro-error(via yew and monaco).unsafe-libyamlviaserde_yaml_ng),which affects
mainas well and is left to be handled there.TODO.md.Review
This PR is large (~23k lines of code; ~118k lines are test data under
etc/test-data). It couldbe split into ingestion changes / correlation engine / UI if that helps reviewing.
Test plan
cargo test -p trustify-module-correlation: scenario tests (etc/test-data/scenarios, eachrun in both ingestion orders) against real advisories (Red Hat, SUSE, OSV, CVE, CERT@VDE), incl.
S24, a syft SBOM of a UBI 10 image
cargo xtask precommit(includes the UI crate)Try it out
ui/(needsrustup target add wasm32-unknown-unknown,cargo install trunk, and Node.js; seeui/README.md):cd ui npm ci trunk serve --port 8081🤖 Generated with Claude Code