feat: exploit intelligence integration - #2534
Conversation
There was a problem hiding this comment.
Sorry @Strum355, your pull request is larger than the review limit of 150000 diff characters
068214e to
c74a322
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2534 +/- ##
==========================================
+ Coverage 72.13% 72.75% +0.61%
==========================================
Files 466 483 +17
Lines 28634 30166 +1532
Branches 28634 30166 +1532
==========================================
+ Hits 20654 21946 +1292
- Misses 6810 6974 +164
- Partials 1170 1246 +76 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
ctron
left a comment
There was a problem hiding this comment.
I think that, unless impossible, this should go into it's own module. It doesn't seem to be "fundemental".
Also, how can the UI evaluate if this feature is configured or not?
ruromero
left a comment
There was a problem hiding this comment.
Review: Exploit Intelligence Integration
Solid feature with well-designed job queue, comprehensive tests, and good resilience patterns. The convention and code quality items below should be addressed before merge.
See inline comments for details.
Thanks for pointing this out, seems my changes disappeared into a git stash. Im taking the approach of adding a flag to {"version":"0.5.0-rc.1","readOnly":false,"exploitIntelligence":false,"build":{...}}
Ill have a look into this 👍 |
4e515b5 to
fe36624
Compare
db0c4ef to
de5108a
Compare
|
The command line arguments of EI mix with others and are inconsistently named: |
|
When setting the EI URL, but not the EI UI URL, what's expected to happen? |
|
Are |
|
Looks like a great improvement. Less complex. Lot of minor things to clean up. Error handling, types, imports and common stuff. Also I noticed that the arguments are still mixed: EI is claiming other settings. |
- Renumber migration m0002270 → m0002280 to avoid collision with PR guacsec#2534 - Add comment explaining no-op down() in data-fix migration - Document CVSS score preference order in cvss.rs - Add generation provenance to SQL test dump files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code
Remove the m0002270 → m0002280 rename — the collision with PR guacsec#2534 does not apply after rebase. Retain the doc comments and test dump provenance headers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ion (#2435) Create database entities and migration for tracking Exploit Intelligence analysis jobs. Every job has at least one component row — CycloneDX single-component jobs get exactly one, SPDX product jobs get N. Job table tracks lifecycle (sbom_id, vulnerability_id, status) while all per-component results (scan_id, finding, advisory_id) live exclusively on the component table. Report URLs are derived at query time from config + scan_id, not stored. Includes composite index on (sbom_id, vulnerability_id) for the find_active_job deduplication query, and FK indexes per CONVENTIONS.md. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ints (#2464) Implements TC-4677
- Renumber EI migration from m0002250 to m0002270 to resolve collision with m0002250_create_cpe_status - Move create.exploitIntelligence permission from read:document to create:document scope (write operations should not be gated by read-only access) - Remove duplicate doc comment on compute_job_report_url Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 17 service-level tests covering job creation, dedup, dequeue
mechanics (visibility timeout, retry exhaustion, batch limit),
status guard enforcement, failure cascade to components, visibility
extension, component lifecycle, and excluded component semantics.
Add 12 runner-level tests using wiremock to mock the EI service API,
covering both CycloneDX and SPDX flows: successful analysis with
findings, VEX advisory ingestion, EI-side analysis failure, upload
rejection, transient retry, all-excluded products, mixed components,
product-level failure, and error classification.
Fix advisory_id not being linked to components after VEX ingestion
(strip_prefix("urn:uuid:") failed when the ingestor returned a
plain UUID without the prefix).
Fix dequeue_jobs returning stale pre-update models by reflecting
the UPDATE in memory before returning.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…te of EI support is enabled
…-intelligence - New crate modules/exploit-intelligence/ (trustify-module-exploit-intelligence) with its own Error type (3 variants: Unavailable, Database, Any) and ResponseError impl - Moved all 13 EI source files, updated crate::exploit_intelligence:: → crate:: paths, replaced SourceDocument round-trip with direct StorageKey::from_sha256() - Cleaned fundamental: removed pub mod exploit_intelligence, removed ei_service parameter from configure(), removed backon/reqwest/bytes from deps, removed EI imports from 5 integration test files and test helpers - Rewired server: imports now come from trustify_module_exploit_intelligence, EI endpoints mounted directly in /api scope alongside importer/ingestor/fundamental
- Use find_also_related join instead of two sequential queries - Use try_collect::<BytesMut> for stream collection - Split run_analysis: extract upload_sbom helper - Match on Format enum instead of if/else - Avoid unnecessary clone with as_deref - Import reqwest::multipart types and clean up inline paths - Replace Cell<u32> with AtomicU32 for retry counters - Add EiRequestError::Pending variant replacing string sentinel - Add EiRequestError::Rejected for 4xx with user_message() sanitization - Use TrustifyQuery + Filtering for generic job list query/filtering - Handle duplicate key on concurrent create_job gracefully (return 200) - Log UUID parse failures in VEX ingestion - Log mark_failed DB errors in worker - Replace log::warn with tracing::warn, remove log dep - Rename ei_client.rs to client.rs - Nest service imports, clean up inline paths across model/polling/worker - Use strum::IntoStaticStr for status_expr instead of manual match - Remove dead From<JobStatus> and ProductComponent - Return Result<_, Error> from endpoints, remove map_err boilerplate - Add NotFound, Query, From<DbError> to error type - Accept String path param for job ID, return 404 on invalid UUID - Add ProductState enum for product_state field - Fall back to EI URL when UI URL not set - Rename --worker-poll-interval to --exploit-intelligence-worker-poll-interval - Enforce mutual exclusion between auth token and OIDC via conflicts_with - Add server tests for well-known EI enabled and analyze 503 when disabled Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… SKIP LOCKED model Rewrite the EI worker from a visibility-timeout + backon retry model to a simpler per-tick held-lock model as requested by ctron. Each worker tick: BEGIN TX → SELECT FOR UPDATE SKIP LOCKED LIMIT 1 → process (upload or poll) → COMMIT. On error: ROLLBACK → increment retry_count outside TX. Permanent errors (4xx, parse failures, missing data) fail the job immediately without burning retries. Key changes: - Replace dequeue_jobs/extend_visibility/fail_exhausted_jobs with claim_one_job returning an open transaction - Remove backon dependency — retry spacing comes from worker_poll_interval - Split run_analysis into process_pending (upload) and process_running (single poll per tick) - Add AnalysisError enum (Retryable/Permanent) with typed From impls for granular error classification - Add poll cooldown: Running jobs not re-claimed until worker_poll_interval has elapsed since last update - Simplify config: remove 5 polling/retry knobs, add max_retries and concurrency (N independent worker loops via LocalSet) - Remove visible_at column from entity and migration (never deployed) - Remove AllowNotUpdated status guards (SKIP LOCKED prevents races) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Internal error details (HTTP status codes, EI response bodies) should not be exposed to API consumers. The raw error remains in the database column and server logs for operators. The UI handles user-facing messaging based on the job status. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… dedup - Remove copied JobStatus/JobFinding enums; use entity enums directly with Serialize/Deserialize/ToSchema derives - Rename Finding → ExploitIntelligenceFinding for OpenAPI consistency - Replace multi-pass ComponentCounts with single-pass fold - Make PollResponse.status and ProductReportEntry.state enums (ReportStatus) - Extract ei_get<T> helper to deduplicate HTTP request/classify/parse - Extract parse_justification_status to deduplicate finding mapping - Add PollResponse::vex() accessor - Replace anyhow wrappers with typed From impls; thiserror #[from] - Remove redundant find_active_job pre-check from analyze endpoint - Use db_ro for duplicate-key fallback read - Remove backon from workspace Cargo.toml - Move EI args to end of Run struct to fix CLI help grouping - Add shutdown signal via oneshot channel (RAII drop on server exit) - Move all inline qualified paths to file-level imports Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
05ecbd4 to
f715b7f
Compare
Summary
Feature branch merge for Exploit Intelligence integration.
Tasks implemented:
Implements TC-4441
Related trustify-ui PR: guacsec/trustify-ui#1125