Skip to content

feat: add support for CSAF advisories with CPE-based product IDs instead of PURLs#2257

Merged
ctron merged 4 commits intoguacsec:mainfrom
Strum355:nsc/redhat-csaf-remediations
Mar 30, 2026
Merged

feat: add support for CSAF advisories with CPE-based product IDs instead of PURLs#2257
ctron merged 4 commits intoguacsec:mainfrom
Strum355:nsc/redhat-csaf-remediations

Conversation

@Strum355
Copy link
Copy Markdown
Member

@Strum355 Strum355 commented Feb 24, 2026

Summary by Sourcery

Extend vulnerability analysis to include CSAF product_status data with CPE-based product identifiers alongside existing PURL-based matching.

New Features:

  • Support resolving vulnerabilities from CSAF product_status entries that reference packages by CPE-based product context rather than only by PURL.
  • Expose CPE context on purl status results derived from CSAF advisories, including associated version ranges and remediations.

Enhancements:

  • Pre-fetch and cache CPE entities during analysis to efficiently enrich advisory results with CPE context metadata.
  • Combine PURL-based and product_status-based vulnerability queries into a unified analysis path for requested packages.

Tests:

  • Add integration tests covering CSAF advisories that use product_status with CPE-based product identifiers, validating affected status, CPE context, and remediation categories for Maven packages with and without namespaces.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Feb 24, 2026

Reviewer's Guide

Extends vulnerability analysis to incorporate CSAF product_status entries that reference products by CPE instead of PURL, by prefetching CPE records, expanding SQL to union product_status-based advisories, threading CPE context through the analysis pipeline, and adding tests to validate behavior on real CSAF documents.

Sequence diagram for CPE-aware vulnerability analysis pipeline

sequenceDiagram
    actor Client
    participant VulnerabilityService
    participant DB as Database
    participant CPEMap as cpe_map
    participant PurlStatus

    Client->>VulnerabilityService: analyze_vulnerabilities(connection, purls)
    Note over VulnerabilityService: Fetch purl_status and product_status data
    VulnerabilityService->>DB: SELECT ... FROM purl_status ...
    DB-->>VulnerabilityService: purl_status rows (JSON advisories)
    VulnerabilityService->>DB: SELECT ... FROM product_status LEFT JOIN cpe ...
    DB-->>VulnerabilityService: product_status rows (JSON advisories with context_cpe)

    Note over VulnerabilityService: Collect IDs from JSONB advisories
    VulnerabilityService->>VulnerabilityService: extract advisory_id, context_cpe into sets
    VulnerabilityService->>DB: SELECT * FROM advisory WHERE id = ANY(advisory_ids)
    DB-->>VulnerabilityService: advisory models
    VulnerabilityService->>DB: SELECT * FROM cpe WHERE id = ANY(cpe_ids)
    DB-->>VulnerabilityService: cpe models
    VulnerabilityService->>CPEMap: build HashMap<Uuid, cpe_Model>

    Note over VulnerabilityService: Build analysis details per PURL
    loop for each purl
        VulnerabilityService->>VulnerabilityService: deserialize AdvisoryEntryDetailsPhase (includes context_cpe)
        alt context_cpe present
            VulnerabilityService->>CPEMap: lookup cpe_model by id
            CPEMap-->>VulnerabilityService: cpe_Model
            VulnerabilityService->>VulnerabilityService: cpe_string = cpe_Model.to_string()
        else no context_cpe
            VulnerabilityService->>VulnerabilityService: cpe_string = None
        end
        VulnerabilityService->>PurlStatus: from_head(head, advisory_head, purl, status, version_range, cpe_string, scores)
        PurlStatus-->>VulnerabilityService: PurlStatus instance
    end

    VulnerabilityService-->>Client: AnalysisData and AnalysisDetailsV3
Loading

Class diagram for updated vulnerability analysis data flow with CPE support

classDiagram
    class VulnerabilityService {
        +analyze_vulnerabilities(connection, purls) Result~AnalysisData~
        +build_analysis_details_v3(connection, head, purl, descriptions_map, scores_map, advisories_map, cpe_map) Result~tuple~
    }

    class AnalysisData {
        +purls_with_vulnerabilities : Vec
        +warnings : Vec
        +descriptions_map : HashMap~String, vulnerability_description_Model~
        +scores : Vec~advisory_vulnerability_score_Model~
        +advisories_map : HashMap~Uuid, AdvisoryData~
        +cpe_map : HashMap~Uuid, cpe_Model~
    }

    class AdvisoryEntryQueryPhase {
        +advisory_id : Uuid
        +context_cpe : Option~Uuid~
    }

    class AdvisoryEntryDetailsPhase {
        +status : String
        +advisory_id : Uuid
        +version_range : VersionRange
        +remediations : Vec~RemediationEntry~
        +context_cpe : Option~Uuid~
    }

    class cpe_Model {
        +id : Uuid
        +to_string() String
    }

    class PurlStatus {
        +from_head(head, advisory_head, purl, status, version_range, context_cpe_string, scores) Result~PurlStatus~
    }

    class AdvisoryData {
        <<struct>>
    }

    class VersionRange {
        <<struct>>
    }

    class RemediationEntry {
        <<struct>>
    }

    class AnalysisDetailsV3 {
        <<struct>>
    }

    class AnalysisPurlStatus {
        +purl_status : PurlStatus
    }

    VulnerabilityService --> AnalysisData : builds
    VulnerabilityService --> AnalysisDetailsV3 : builds
    AnalysisData --> cpe_Model : uses as map values
    AnalysisData --> AdvisoryData : uses as map values
    VulnerabilityService --> AdvisoryEntryQueryPhase : deserializes from JSONB
    VulnerabilityService --> AdvisoryEntryDetailsPhase : deserializes from JSONB
    VulnerabilityService --> cpe_Model : prefetches
    VulnerabilityService --> PurlStatus : constructs via from_head
    PurlStatus --> cpe_Model : optional context via to_string
    AnalysisDetailsV3 --> AnalysisPurlStatus : contains
    AnalysisPurlStatus --> PurlStatus : wraps
Loading

Flow diagram for building combined purl_status and product_status SQL

flowchart TD
    A[Start: build SQL for a requested PURL] --> B[Determine namespace condition for base_purl]
    B --> C[Build purl_status_sql string
SELECT ... FROM purl_status ...]
    C --> D[Create purl_status_query using Statement::from_sql_and_values
with requested_purl, name, type, version]

    D --> E[Determine package_condition
- if namespace present: product_status.package = full_name OR name
- else: product_status.package = name]

    E --> F[Build product_status_sql string
SELECT ... FROM product_status
JOIN status, vulnerability, product_version_range, version_range
LEFT JOIN cpe ON product_status.context_cpe_id = cpe.id
WHERE package_condition AND product_status.package IS NOT NULL
AND status.slug NOT IN fixed, not_affected, recommended]

    F --> G[Create product_status_query using Statement::from_sql_and_values
with requested_purl]

    G --> H[Concatenate SQL
final_sql = purl_status_query UNION ALL product_status_query]
    H --> I[Return final_sql for execution]
Loading

File-Level Changes

Change Details Files
Pre-fetch and thread CPE models through vulnerability analysis pipeline so CPE context can be attached to purl statuses.
  • Extend AnalysisData to include a CPE ID to model map and populate it when analyzing PURLs.
  • Parse optional context_cpe UUIDs from advisory JSON entries and collect unique CPE IDs.
  • Query CPE entities by collected IDs and store them in a HashMap keyed by ID for later lookup.
  • Pass the CPE map into analyze_purl_v3 and related helpers, and use it to render a human-readable CPE string on each PurlStatus when context_cpe is present.
modules/fundamental/src/vulnerability/service/mod.rs
Augment SQL used in analyze_purls_v3 so CSAF product_status entries are considered alongside legacy PURL-based advisories, including CPE context and remediations.
  • Refactor existing PURL-based SQL into purl_status_sql and keep its behavior intact.
  • Introduce a package_condition fragment that matches product_status.package against either full namespace/name or bare name depending on whether the PURL has a namespace.
  • Add a new product_status_sql query that joins product_status, status, vulnerability, product_version_range, version_range, remediation_product_status, remediation, and CPE to build advisories JSON including status, advisory_id, context_cpe, version_range, and remediations.
  • Return a UNION ALL of the PURL-based and product_status-based queries so both advisory sources contribute to the analysis.
modules/fundamental/src/vulnerability/service/mod.rs
Extend advisory JSON decoding and PurlStatus construction to carry CPE context and support product_status-backed advisories.
  • Add context_cpe field to AdvisoryEntry used when decoding advisories JSON in analyze_purl_v3.
  • Lookup the CPE string via the CPE map using context_cpe and pass it into PurlStatus::from_head as the context argument instead of always passing None.
  • Ensure score calculation paths ignore the CPE map where not needed by destructuring it as unused in those code paths.
modules/fundamental/src/vulnerability/service/mod.rs
Add integration tests covering product_status-based vulnerability resolution, CPE context, and remediations for specific CSAF documents.
  • Add analyze_purls_product_status test that ingests CSAF documents for CVE-2023-20862 and CVE-2023-0044, then asserts affected statuses, presence of CPE context, and expected remediation categories for spring-security and io.quarkus/quarkus-vertx-http packages.
  • Add analyze_purls_product_status_0044 test that focuses on a namespaced io.quarkus/quarkus-vertx-http PURL and verifies it yields CVE-2023-0044 details and exactly two remediations from product_status contexts.
modules/fundamental/src/vulnerability/service/test.rs

Possibly linked issues

  • #CSAF Remediation - product statuses: The PR implements analyze endpoint support for CSAF product_status, CPE context, and remediations exactly as described in the issue.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • The dynamic SQL composition for package_condition and product_status_sql relies on Statement::to_string() and string interpolation, which is brittle and backend-specific; consider using SeaORM's query builder (or consistently tracked parameter lists) to avoid subtle issues with placeholders and SQL injection/escaping.
  • There is a println! left in analyze_purls_product_status that prints remediations during the test run; consider removing or converting this to a log call to keep test output clean.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The dynamic SQL composition for `package_condition` and `product_status_sql` relies on `Statement::to_string()` and string interpolation, which is brittle and backend-specific; consider using SeaORM's query builder (or consistently tracked parameter lists) to avoid subtle issues with placeholders and SQL injection/escaping.
- There is a `println!` left in `analyze_purls_product_status` that prints remediations during the test run; consider removing or converting this to a `log` call to keep test output clean.

## Individual Comments

### Comment 1
<location path="modules/fundamental/src/vulnerability/service/mod.rs" line_range="537-546" />
<code_context>
                 );

-                Ok(Some(query.to_string()))
+                let package_condition = match &purl.namespace {
+                    Some(namespace) => {
+                        let full_name = format!("{}/{}", namespace, purl.name);
+                        let sql = "(product_status.package = $1 OR product_status.package = $2)";
+                        Statement::from_sql_and_values(
+                            connection.get_database_backend(),
+                            sql,
+                            [full_name.into(), purl.name.clone().into()],
+                        )
+                        .to_string()
+                    }
+                    None => {
</code_context>
<issue_to_address>
**issue (bug_risk):** Building `package_condition` via `Statement::to_string()` is brittle and may silently depend on SeaORM’s debug formatting/parameter inlining behavior.

This approach couples `package_condition` to SeaORM’s `Statement::to_string()` debug behavior and its current choice to inline bound parameters. If SeaORM changes `to_string()` to keep `$1`/`$2` placeholders, `product_status_sql` will contain unbound parameters since `product_status_query` only supplies `[p.into()]`, leading to runtime errors or parameter mismatches.

Prefer either building `package_condition` as plain SQL with explicit, safely-escaped interpolations, or representing the entire `product_status_sql` as a single `Statement` with all bindings managed together, rather than embedding a stringified `Statement`.
</issue_to_address>

### Comment 2
<location path="modules/fundamental/src/vulnerability/service/test.rs" line_range="933-939" />
<code_context>
+        "All statuses should be affected"
+    );
+
+    // Should have CPE context on statuses
+    assert!(
+        details
+            .purl_statuses
+            .iter()
+            .any(|s| s.purl_status.context.is_some()),
+        "Should have CPE context from product_status"
+    );
+
</code_context>
<issue_to_address>
**suggestion (testing):** Strengthen CPE context assertions to verify the actual CPE value, not only presence

This assertion only checks that *some* `purl_status.context` is `Some`, so it would still pass with the wrong CPE or a changed format. To properly validate the new `context_cpe` wiring, assert that the returned `context` values include the specific expected CPE string(s) from the CSAF (e.g. compare against a known `"cpe:2.3:..."`), so the `cpe_map` join and `PurlStatus` serialization are actually verified.

Suggested implementation:

```rust
    // All statuses should be "affected" (from known_affected)
    assert!(
        details
            .purl_statuses
            .iter()
            .all(|s| s.purl_status.status == "affected"),
        "All statuses should be affected"
    );

    // Should have CPE context on statuses and it should match the expected CPE(s)
    let contexts: Vec<&str> = details
        .purl_statuses
        .iter()
        .filter_map(|s| s.purl_status.context.as_deref())
        .collect();

    assert!(
        !contexts.is_empty(),
        "Expected at least one PurlStatus to have CPE context"
    );

    // Verify that the expected CPE from the CSAF is present in the contexts.
    // NOTE: replace the placeholder CPE string with the specific value from the CSAF fixture.
    let expected_cpe = "cpe:2.3:REPLACE_ME_WITH_EXPECTED_CPE_FROM_CSAF";
    assert!(
        contexts.iter().any(|c| *c == expected_cpe),
        "Expected CPE context `{}` not found in PurlStatus contexts: {:?}",
        expected_cpe,
        contexts
    );


```

To fully implement the intent of the review comment, update the `expected_cpe` placeholder string to the actual CPE value present in the `csaf/CVE-2023-20862.json` (or the relevant CSAF fixture for this test).  
If multiple distinct CPEs are expected, you can extend this check by:
1. Defining a `Vec<&str>` or `HashSet<&str>` of expected CPEs.
2. Asserting that each expected CPE is contained in `contexts` (e.g. with `all(|expected| contexts.contains(expected))`).
</issue_to_address>

### Comment 3
<location path="modules/fundamental/src/vulnerability/service/test.rs" line_range="1033-1038" />
<code_context>
+    let details = &analysis.details[0];
+    assert_eq!(details.head.identifier, "CVE-2023-0044");
+
+    let remediations = details
+        .purl_statuses
+        .iter()
+        .flat_map(|status| status.remediations.clone())
+        .collect_vec();
+    assert_eq!(remediations.len(), 2);
+
+    Ok(())
</code_context>
<issue_to_address>
**suggestion (testing):** Make the remediation assertions more specific than just counting entries

Here, the test only checks that there are 2 remediations, so it would still pass if their categories or contents changed. Since this test is specific to `cve-2023-0044.json`, please also assert the expected remediation categories (e.g., `Workaround` and `NoneAvailable`) and, if possible, that key fields like `details` or `url` are present. That will better guard the product_status→remediation mapping for namespaced packages.

Suggested implementation:

```rust
    let details = &analysis.details[0];
    assert_eq!(details.head.identifier, "CVE-2023-0044");

    let remediations = details
        .purl_statuses
        .iter()
        .flat_map(|status| status.remediations.iter())
        .collect_vec();
    assert_eq!(remediations.len(), 2, "Expected exactly two remediations for CVE-2023-0044");

    // Ensure we have the expected remediation categories for this CSAF document
    let categories = remediations
        .iter()
        .map(|remediation| &remediation.category)
        .collect_vec();

    assert!(
        categories.iter().any(|c| matches!(c, RemediationCategory::Workaround)),
        "Expected at least one remediation with category Workaround"
    );
    assert!(
        categories.iter().any(|c| matches!(c, RemediationCategory::NoneAvailable)),
        "Expected at least one remediation with category NoneAvailable"
    );

    // Ensure each remediation has some meaningful content attached
    for remediation in remediations {
        assert!(
            remediation.details.is_some() || remediation.url.is_some(),
            "Each remediation should have either details text or a URL"
        );
    }

```

You may need to:
1. Import or qualify the `RemediationCategory` enum at the top of this file, for example:
   `use trustify_csaf::model::RemediationCategory;`
   or whatever path is used elsewhere in the codebase.
2. Adjust the field names `details` and `url` on the remediation struct if they differ
   (e.g. `description` instead of `details`), so that the assertions compile correctly.
3. If `status.remediations` is already a slice or reference type, you can keep using
   `.clone()` as in the original code; I switched to iterating by reference with
   `.iter()` to avoid unnecessary cloning, but you can align this with the existing
   conventions in the file.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread modules/fundamental/src/vulnerability/service/mod.rs
Comment on lines +933 to +939
// Should have CPE context on statuses
assert!(
details
.purl_statuses
.iter()
.any(|s| s.purl_status.context.is_some()),
"Should have CPE context from product_status"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Strengthen CPE context assertions to verify the actual CPE value, not only presence

This assertion only checks that some purl_status.context is Some, so it would still pass with the wrong CPE or a changed format. To properly validate the new context_cpe wiring, assert that the returned context values include the specific expected CPE string(s) from the CSAF (e.g. compare against a known "cpe:2.3:..."), so the cpe_map join and PurlStatus serialization are actually verified.

Suggested implementation:

    // All statuses should be "affected" (from known_affected)
    assert!(
        details
            .purl_statuses
            .iter()
            .all(|s| s.purl_status.status == "affected"),
        "All statuses should be affected"
    );

    // Should have CPE context on statuses and it should match the expected CPE(s)
    let contexts: Vec<&str> = details
        .purl_statuses
        .iter()
        .filter_map(|s| s.purl_status.context.as_deref())
        .collect();

    assert!(
        !contexts.is_empty(),
        "Expected at least one PurlStatus to have CPE context"
    );

    // Verify that the expected CPE from the CSAF is present in the contexts.
    // NOTE: replace the placeholder CPE string with the specific value from the CSAF fixture.
    let expected_cpe = "cpe:2.3:REPLACE_ME_WITH_EXPECTED_CPE_FROM_CSAF";
    assert!(
        contexts.iter().any(|c| *c == expected_cpe),
        "Expected CPE context `{}` not found in PurlStatus contexts: {:?}",
        expected_cpe,
        contexts
    );

To fully implement the intent of the review comment, update the expected_cpe placeholder string to the actual CPE value present in the csaf/CVE-2023-20862.json (or the relevant CSAF fixture for this test).
If multiple distinct CPEs are expected, you can extend this check by:

  1. Defining a Vec<&str> or HashSet<&str> of expected CPEs.
  2. Asserting that each expected CPE is contained in contexts (e.g. with all(|expected| contexts.contains(expected))).

Comment on lines +1033 to +1038
let remediations = details
.purl_statuses
.iter()
.flat_map(|status| status.remediations.clone())
.collect_vec();
assert_eq!(remediations.len(), 2);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Make the remediation assertions more specific than just counting entries

Here, the test only checks that there are 2 remediations, so it would still pass if their categories or contents changed. Since this test is specific to cve-2023-0044.json, please also assert the expected remediation categories (e.g., Workaround and NoneAvailable) and, if possible, that key fields like details or url are present. That will better guard the product_status→remediation mapping for namespaced packages.

Suggested implementation:

    let details = &analysis.details[0];
    assert_eq!(details.head.identifier, "CVE-2023-0044");

    let remediations = details
        .purl_statuses
        .iter()
        .flat_map(|status| status.remediations.iter())
        .collect_vec();
    assert_eq!(remediations.len(), 2, "Expected exactly two remediations for CVE-2023-0044");

    // Ensure we have the expected remediation categories for this CSAF document
    let categories = remediations
        .iter()
        .map(|remediation| &remediation.category)
        .collect_vec();

    assert!(
        categories.iter().any(|c| matches!(c, RemediationCategory::Workaround)),
        "Expected at least one remediation with category Workaround"
    );
    assert!(
        categories.iter().any(|c| matches!(c, RemediationCategory::NoneAvailable)),
        "Expected at least one remediation with category NoneAvailable"
    );

    // Ensure each remediation has some meaningful content attached
    for remediation in remediations {
        assert!(
            remediation.details.is_some() || remediation.url.is_some(),
            "Each remediation should have either details text or a URL"
        );
    }

You may need to:

  1. Import or qualify the RemediationCategory enum at the top of this file, for example:
    use trustify_csaf::model::RemediationCategory;
    or whatever path is used elsewhere in the codebase.
  2. Adjust the field names details and url on the remediation struct if they differ
    (e.g. description instead of details), so that the assertions compile correctly.
  3. If status.remediations is already a slice or reference type, you can keep using
    .clone() as in the original code; I switched to iterating by reference with
    .iter() to avoid unnecessary cloning, but you can align this with the existing
    conventions in the file.

@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 24, 2026

Codecov Report

❌ Patch coverage is 97.71429% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.89%. Comparing base (e116e98) to head (8f40eaa).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
...dules/fundamental/src/vulnerability/service/mod.rs 98.57% 0 Missing and 2 partials ⚠️
...ules/fundamental/src/vulnerability/service/test.rs 93.10% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2257      +/-   ##
==========================================
+ Coverage   67.71%   67.89%   +0.18%     
==========================================
  Files         433      434       +1     
  Lines       24875    25018     +143     
  Branches    24875    25018     +143     
==========================================
+ Hits        16843    16985     +142     
+ Misses       7111     7104       -7     
- Partials      921      929       +8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Strum355
Copy link
Copy Markdown
Member Author

Strum355 commented Feb 24, 2026

Output from /v3/vulnerability/analyze output given https://github.com/guacsec/trustify/blob/main/etc/test-data/csaf/cve-2023-0044.json document for the purl pkg:maven/io.quarkus/quarkus-vertx-http@1.0.0:

{
  "vulnerability": {
    "normative": true,
    "identifier": "CVE-2023-0044",
    "title": null,
    "description": null,
    "reserved": null,
    "published": null,
    "modified": null,
    "withdrawn": null,
    "discovered": null,
    "released": null,
    "cwes": []
  },
  "advisory": {
    "uuid": "urn:uuid:dc6d3239-ddaa-4241-81ad-910dfe143d0e",
    "identifier": "https://www.redhat.com/#CVE-2023-0044",
    "document_id": "CVE-2023-0044",
    "issuer": {
      "id": "88d35642-663a-4daa-9982-590d74a7409d",
      "name": "Red Hat Product Security",
      "cpe_key": null,
      "website": null
    },
    "published": "2023-01-04T00:00:00Z",
    "modified": "2023-11-13T11:31:31Z",
    "withdrawn": null,
    "title": "quarkus-vertx-http: a cross-site attack may be initiated which might lead to the Information Disclosure",
    "labels": {
      "source": "TrustifyContext",
      "type": "csaf"
    }
  },
  "scores": [
    {
      "type": "3.1",
      "value": 5.3,
      "severity": "medium"
    }
  ],
  "average_severity": "medium",
  "average_score": 5.3,
  "status": "affected",
  "context": {
    "cpe": "cpe:/a:redhat:quarkus:2:*:*:*"
  },
  "version_range": {
    "version_scheme_id": "rpm",
    "low_version": "2.0.0",
    "low_inclusive": true,
    "high_version": "3.0.0",
    "high_inclusive": false
  },
  "remediations": [
    {
      "id": "b8e80493-7c71-5e98-a584-9cd0fc4434d5",
      "category": "workaround",
      "details": "This attack can be prevented with the Quarkus CSRF Prevention feature.",
      "url": null,
      "data": {
        "details": "This attack can be prevented with the Quarkus CSRF Prevention feature.",
        "category": "workaround",
        "product_ids": [
          "Red Hat build of Quarkus",
          "Red Hat build of Quarkus 2.7.7",
          "a-mq_clients_2:quarkus-vertx-http",
          "red_hat_build_of_quarkus:io.quarkus/quarkus-vertx-http",
          "red_hat_integration_camel_k:quarkus-vertx-http",
          "red_hat_integration_camel_quarkus:quarkus-vertx-http",
          "red_hat_integration_change_data_capture:quarkus-vertx-http",
          "red_hat_integration_service_registry:quarkus-vertx-http",
          "red_hat_jboss_enterprise_application_platform_7:quarkus-vertx-http",
          "red_hat_jboss_enterprise_application_platform_expansion_pack:quarkus-vertx-http",
          "red_hat_jboss_fuse_7:quarkus-vertx-http",
          "red_hat_process_automation_7:quarkus-vertx-http"
        ]
      }
    },
    {
      "id": "e2826a19-8598-5e67-bab2-4fe1a4c33583",
      "category": "none_available",
      "details": "Affected",
      "url": null,
      "data": {
        "details": "Affected",
        "category": "none_available",
        "product_ids": [
          "red_hat_build_of_quarkus:io.quarkus/quarkus-vertx-http"
        ]
      }
    }
  ]
}

@ctron
Copy link
Copy Markdown
Contributor

ctron commented Feb 27, 2026

Sorry for asking maybe basic questions, I wasn't part of the discussions up until now. I'd like to understand the motivation.

If the user provides an SBOM (most likely, of their own project), which contains a package pkg:maven/io.quarkus/quarkus-vertx-http@1.0.0, the user would get back the information, that the product red_hat_jboss_fuse_7:quarkus-vertx-http is affected, but a workaround exists.

I am not sure, that this is what users are looking for. So, is that the intention?

@Strum355
Copy link
Copy Markdown
Member Author

If the user provides an SBOM (most likely, of their own project), which contains a package pkg:maven/io.quarkus/quarkus-vertx-http@1.0.0, the user would get back the information, that the product red_hat_jboss_fuse_7:quarkus-vertx-http is affected, but a workaround exists.

I am not sure, that this is what users are looking for. So, is that the intention?

The data field is intended to be denormalized/raw underlying data, I brought this up in the original Remedations ADR discussion here for some brief context for you: #2179 (comment)

@ctron
Copy link
Copy Markdown
Contributor

ctron commented Mar 2, 2026

Thanks for linking the PR, that should help me understanding things.

@ctron
Copy link
Copy Markdown
Contributor

ctron commented Mar 2, 2026

If the user provides an SBOM (most likely, of their own project), which contains a package pkg:maven/io.quarkus/quarkus-vertx-http@1.0.0, the user would get back the information, that the product red_hat_jboss_fuse_7:quarkus-vertx-http is affected, but a workaround exists.
I am not sure, that this is what users are looking for. So, is that the intention?

The data field is intended to be denormalized/raw underlying data, I brought this up in the original Remedations ADR discussion here for some brief context for you: #2179 (comment)

After reading this, I'm still not sure that this what the user wants. But to my understanding you all discussed this and this is what we want.

@ctron
Copy link
Copy Markdown
Contributor

ctron commented Mar 2, 2026

It looks like the PR does some significant changes on database queries. So I want to be sure to understand the performance impact on this.

Which endpoints would be affected by this? And do we have tests in scale testing (https://github.com/guacsec/trustify-scale-testing/blob/main/src/restapi.rs) covering them? If not, we should add them first. As those endpoints seem to exist already. This PR is just adding more data to it.

Copy link
Copy Markdown
Contributor

@ctron ctron Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is getting a bit too big. We should start splitting it up.


let product_status_sql = format!(
r#"
SELECT
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot of code duplication with the previous SQL statement. It should be possible to reduce that by introducing a common function, helping to build that statement.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ive tried to address this in the below commit, let me know if this works for you or youd rather a different approach?
e32ad98

Comment thread modules/fundamental/src/vulnerability/service/mod.rs

#[test_context(TrustifyContext)]
#[test(tokio::test)]
async fn analyze_purls_product_status(ctx: &TrustifyContext) -> Result<(), anyhow::Error> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to have a quick summary of with both tests are supposed to test.


#[test_context(TrustifyContext)]
#[test(tokio::test)]
async fn analyze_purls_product_status(ctx: &TrustifyContext) -> Result<(), anyhow::Error> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not transform those tests into endpoint tests? Covering the endpoint handling as well.

@ctron
Copy link
Copy Markdown
Contributor

ctron commented Mar 2, 2026

I just tried the PR, and peeked at the response from the service function. I'm struggling to understand the output. Which might also indicate that the tests need to be firmed up a bit. Not only checked if expected information is in there. But also that non-expected information is not part. Maybe just falling back to a simple pattern of result == json!({}).

Running analyze_purls_product_status, I get back:

For pkg:maven/spring-security@1.0.0, an entry of CVE-2023-20862, having an advisory of https://www.redhat.com/#CVE-2023-20862", which claims a CPE of cpe:/a:redhat:jboss_fuse_service_works:6:*:*:*.

For remediations of this entry, I get:

data: Object {
    "details": String("Out of support scope"),
    "category": String("no_fix_planned"),
    "product_ids": Array [
        String("red_hat_decision_manager_7:spring-security"),
        String("red_hat_jboss_a-mq_6:spring-security"),
        String("red_hat_jboss_enterprise_application_platform_6:spring-security"),
        String("red_hat_jboss_fuse_6:spring-security"),
        String("red_hat_jboss_fuse_7:spring-security"),
        String("red_hat_jboss_fuse_service_works_6:spring-security"),
        String("red_hat_openshift_container_platform_3.11:jenkins"),
        String("red_hat_process_automation_7:spring-security"),
    ],
},

I don't understand, why I get red_hat_openshift_container_platform_3.11:jenkins for cpe:/a:redhat:jboss_fuse_service_works:6:*:*:*.

cve-2023-0044.json doesn't seem to be relevant for this part.

CVE-2023-20862.json seems to be. However, to my understanding, it says that jenkins is affected:

image

jenkins is a component of openshift_developer_tools_and_services, which has a CPE of cpe:/a:redhat:ocp_tools.

So it looks like something doesn't add up here. Or maybe I don't understand it.

@Strum355
Copy link
Copy Markdown
Member Author

Strum355 commented Mar 5, 2026

Running analyze_purls_product_status, I get back:

For pkg:maven/spring-security@1.0.0, an entry of CVE-2023-20862, having an advisory of https://www.redhat.com/#CVE-2023-20862", which claims a CPE of cpe:/a:redhat:jboss_fuse_service_works:6:*:*:*.

For remediations of this entry, I get:

data: Object {
    "details": String("Out of support scope"),
    "category": String("no_fix_planned"),
    "product_ids": Array [
        String("red_hat_decision_manager_7:spring-security"),
        String("red_hat_jboss_a-mq_6:spring-security"),
        String("red_hat_jboss_enterprise_application_platform_6:spring-security"),
        String("red_hat_jboss_fuse_6:spring-security"),
        String("red_hat_jboss_fuse_7:spring-security"),
        String("red_hat_jboss_fuse_service_works_6:spring-security"),
        String("red_hat_openshift_container_platform_3.11:jenkins"),
        String("red_hat_process_automation_7:spring-security"),
    ],
},

I don't understand, why I get red_hat_openshift_container_platform_3.11:jenkins for cpe:/a:redhat:jboss_fuse_service_works:6:*:*:*.

jenkins is a component of openshift_developer_tools_and_services, which has a CPE of cpe:/a:redhat:ocp_tools.

If Im reading the CSAF document right (which I may not be), the remediation linkage seems correct: The reason red_hat_openshift_container_platform_3.11:jenkins appears is because the data field is the raw CSAF remediation JSON from the CSAF document. In the CSAF document, a single remediation entry lists all product_ids it covers (including jenkins), so the raw blob contains them all (link to the specific excerpt in the document here: https://github.com/Strum355/trustify/blob/nsc/redhat-csaf-remediations/etc/test-data/csaf/CVE-2023-20862.json#L670-L683).

Which endpoints would be affected by this? And do we have tests in scale testing (https://github.com/guacsec/trustify-scale-testing/blob/main/src/restapi.rs) covering them? If not, we should add them first. As those endpoints seem to exist already. This PR is just adding more data to it.

The affected endpoints should be /api/v3/purl/recommend and /api/v2/vulnerability/analyze. The former doesn't have any scale tests currently (Ill go ahead and add some), the latter has scale tests (https://github.com/guacsec/trustify-scale-testing/blob/main/src/restapi.rs#L355C33-L368)

Thanks for the review feedback so far! @ctron

@ctron
Copy link
Copy Markdown
Contributor

ctron commented Mar 10, 2026

So, to my understanding, the CSAF document contains a list of vulnerabilities. And each vulnerability lists:

  • a status in the context of a product/component
  • remediations for products/components

So the data is modeled in a way that makes is easy to transport information, for the use case of CSAF.

However, that doesn't mean that just returning the whole section makes sense.

3.2.3.12.6 Vulnerabilities Property - Remediations - Product IDs

Product IDs (product_ids) are of value type Products (products_t) and contain a list of Products the current remediation item applies to.

This field defines for which product IDs this remediation entry relates to. However, when returning a remediation entry for "component A", it doesn't seem to make sense to return the information that the same remediation also applies to "component B".

@Strum355 Strum355 force-pushed the nsc/redhat-csaf-remediations branch 2 times, most recently from 00a3f3d to e95c6cc Compare March 23, 2026 17:38
@Strum355
Copy link
Copy Markdown
Member Author

Output for vulnerability::service::test::analyze_purls_product_status test with PURL pkg:maven/spring-security@1.0.0 and CSAF document csaf/CVE-2023-20862.json
[
  {
    "vulnerability": {
      "normative": true,
      "identifier": "CVE-2023-20862",
      "title": null,
      "description": null,
      "reserved": null,
      "published": null,
      "modified": null,
      "withdrawn": null,
      "discovered": null,
      "released": null,
      "cwes": []
    },
    "advisory": {
      "uuid": "urn:uuid:a7d1d4fd-2c59-43c4-944e-92dbca7227e7",
      "identifier": "https://www.redhat.com/#CVE-2023-20862",
      "document_id": "CVE-2023-20862",
      "issuer": {
        "id": "d2241d75-31ca-4d25-8bf6-6eedafa16629",
        "name": "Red Hat Product Security",
        "cpe_key": null,
        "website": null
      },
      "published": "2023-04-19T00:00:00Z",
      "modified": "2023-11-14T22:09:12Z",
      "withdrawn": null,
      "title": "spring-security: Empty SecurityContext Is Not Properly Saved Upon Logout",
      "labels": {
        "type": "csaf",
        "source": "TrustifyContext"
      }
    },
    "scores": [
      {
        "type": "3.1",
        "value": 6.3,
        "severity": "medium"
      }
    ],
    "average_severity": "medium",
    "average_score": 6.3,
    "status": "affected",
    "context": {
      "cpe": "cpe:/a:redhat:jboss_fuse_service_works:6:*:*:*"
    },
    "version_range": {
      "version_scheme_id": "rpm",
      "low_version": "6.0.0",
      "low_inclusive": true,
      "high_version": "7.0.0",
      "high_inclusive": false
    },
    "remediations": [
      {
        "id": "9e1425e8-2502-55ce-9521-6d074cd2141d",
        "category": "no_fix_planned",
        "details": "Out of support scope",
        "url": null,
        "data": {
          "details": "Out of support scope",
          "category": "no_fix_planned",
          "product_ids": [
            "red_hat_jboss_fuse_service_works_6:spring-security"
          ]
        }
      }
    ]
  },
  {
    "vulnerability": {
      "normative": true,
      "identifier": "CVE-2023-20862",
      "title": null,
      "description": null,
      "reserved": null,
      "published": null,
      "modified": null,
      "withdrawn": null,
      "discovered": null,
      "released": null,
      "cwes": []
    },
    "advisory": {
      "uuid": "urn:uuid:a7d1d4fd-2c59-43c4-944e-92dbca7227e7",
      "identifier": "https://www.redhat.com/#CVE-2023-20862",
      "document_id": "CVE-2023-20862",
      "issuer": {
        "id": "d2241d75-31ca-4d25-8bf6-6eedafa16629",
        "name": "Red Hat Product Security",
        "cpe_key": null,
        "website": null
      },
      "published": "2023-04-19T00:00:00Z",
      "modified": "2023-11-14T22:09:12Z",
      "withdrawn": null,
      "title": "spring-security: Empty SecurityContext Is Not Properly Saved Upon Logout",
      "labels": {
        "type": "csaf",
        "source": "TrustifyContext"
      }
    },
    "scores": [
      {
        "type": "3.1",
        "value": 6.3,
        "severity": "medium"
      }
    ],
    "average_severity": "medium",
    "average_score": 6.3,
    "status": "affected",
    "context": {
      "cpe": "cpe:/a:redhat:jboss_amq:6:*:*:*"
    },
    "version_range": {
      "version_scheme_id": "rpm",
      "low_version": "6.0.0",
      "low_inclusive": true,
      "high_version": "7.0.0",
      "high_inclusive": false
    },
    "remediations": [
      {
        "id": "9e1425e8-2502-55ce-9521-6d074cd2141d",
        "category": "no_fix_planned",
        "details": "Out of support scope",
        "url": null,
        "data": {
          "details": "Out of support scope",
          "category": "no_fix_planned",
          "product_ids": [
            "red_hat_jboss_a-mq_6:spring-security"
          ]
        }
      }
    ]
  },
  {
    "vulnerability": {
      "normative": true,
      "identifier": "CVE-2023-20862",
      "title": null,
      "description": null,
      "reserved": null,
      "published": null,
      "modified": null,
      "withdrawn": null,
      "discovered": null,
      "released": null,
      "cwes": []
    },
    "advisory": {
      "uuid": "urn:uuid:a7d1d4fd-2c59-43c4-944e-92dbca7227e7",
      "identifier": "https://www.redhat.com/#CVE-2023-20862",
      "document_id": "CVE-2023-20862",
      "issuer": {
        "id": "d2241d75-31ca-4d25-8bf6-6eedafa16629",
        "name": "Red Hat Product Security",
        "cpe_key": null,
        "website": null
      },
      "published": "2023-04-19T00:00:00Z",
      "modified": "2023-11-14T22:09:12Z",
      "withdrawn": null,
      "title": "spring-security: Empty SecurityContext Is Not Properly Saved Upon Logout",
      "labels": {
        "type": "csaf",
        "source": "TrustifyContext"
      }
    },
    "scores": [
      {
        "type": "3.1",
        "value": 6.3,
        "severity": "medium"
      }
    ],
    "average_severity": "medium",
    "average_score": 6.3,
    "status": "affected",
    "context": {
      "cpe": "cpe:/a:redhat:jboss_enterprise_bpms_platform:7:*:*:*"
    },
    "version_range": {
      "version_scheme_id": "rpm",
      "low_version": "7.0.0",
      "low_inclusive": true,
      "high_version": "8.0.0",
      "high_inclusive": false
    },
    "remediations": [
      {
        "id": "9e1425e8-2502-55ce-9521-6d074cd2141d",
        "category": "no_fix_planned",
        "details": "Out of support scope",
        "url": null,
        "data": {
          "details": "Out of support scope",
          "category": "no_fix_planned",
          "product_ids": [
            "red_hat_process_automation_7:spring-security"
          ]
        }
      }
    ]
  },
  {
    "vulnerability": {
      "normative": true,
      "identifier": "CVE-2023-20862",
      "title": null,
      "description": null,
      "reserved": null,
      "published": null,
      "modified": null,
      "withdrawn": null,
      "discovered": null,
      "released": null,
      "cwes": []
    },
    "advisory": {
      "uuid": "urn:uuid:a7d1d4fd-2c59-43c4-944e-92dbca7227e7",
      "identifier": "https://www.redhat.com/#CVE-2023-20862",
      "document_id": "CVE-2023-20862",
      "issuer": {
        "id": "d2241d75-31ca-4d25-8bf6-6eedafa16629",
        "name": "Red Hat Product Security",
        "cpe_key": null,
        "website": null
      },
      "published": "2023-04-19T00:00:00Z",
      "modified": "2023-11-14T22:09:12Z",
      "withdrawn": null,
      "title": "spring-security: Empty SecurityContext Is Not Properly Saved Upon Logout",
      "labels": {
        "type": "csaf",
        "source": "TrustifyContext"
      }
    },
    "scores": [
      {
        "type": "3.1",
        "value": 6.3,
        "severity": "medium"
      }
    ],
    "average_severity": "medium",
    "average_score": 6.3,
    "status": "affected",
    "context": {
      "cpe": "cpe:/a:redhat:jboss_enterprise_brms_platform:7:*:*:*"
    },
    "version_range": {
      "version_scheme_id": "rpm",
      "low_version": "7.0.0",
      "low_inclusive": true,
      "high_version": "8.0.0",
      "high_inclusive": false
    },
    "remediations": [
      {
        "id": "9e1425e8-2502-55ce-9521-6d074cd2141d",
        "category": "no_fix_planned",
        "details": "Out of support scope",
        "url": null,
        "data": {
          "details": "Out of support scope",
          "category": "no_fix_planned",
          "product_ids": [
            "red_hat_decision_manager_7:spring-security"
          ]
        }
      }
    ]
  },
  {
    "vulnerability": {
      "normative": true,
      "identifier": "CVE-2023-20862",
      "title": null,
      "description": null,
      "reserved": null,
      "published": null,
      "modified": null,
      "withdrawn": null,
      "discovered": null,
      "released": null,
      "cwes": []
    },
    "advisory": {
      "uuid": "urn:uuid:a7d1d4fd-2c59-43c4-944e-92dbca7227e7",
      "identifier": "https://www.redhat.com/#CVE-2023-20862",
      "document_id": "CVE-2023-20862",
      "issuer": {
        "id": "d2241d75-31ca-4d25-8bf6-6eedafa16629",
        "name": "Red Hat Product Security",
        "cpe_key": null,
        "website": null
      },
      "published": "2023-04-19T00:00:00Z",
      "modified": "2023-11-14T22:09:12Z",
      "withdrawn": null,
      "title": "spring-security: Empty SecurityContext Is Not Properly Saved Upon Logout",
      "labels": {
        "type": "csaf",
        "source": "TrustifyContext"
      }
    },
    "scores": [
      {
        "type": "3.1",
        "value": 6.3,
        "severity": "medium"
      }
    ],
    "average_severity": "medium",
    "average_score": 6.3,
    "status": "affected",
    "context": {
      "cpe": "cpe:/a:redhat:camel_quarkus:2:*:*:*"
    },
    "version_range": {
      "version_scheme_id": "rpm",
      "low_version": "2.0.0",
      "low_inclusive": true,
      "high_version": "3.0.0",
      "high_inclusive": false
    },
    "remediations": [
      {
        "id": "d2e4c8ec-d8e8-5d5a-99fa-96823e67335e",
        "category": "no_fix_planned",
        "details": "Will not fix",
        "url": null,
        "data": {
          "details": "Will not fix",
          "category": "no_fix_planned",
          "product_ids": [
            "red_hat_integration_camel_quarkus:spring-security"
          ]
        }
      }
    ]
  },
  {
    "vulnerability": {
      "normative": true,
      "identifier": "CVE-2023-20862",
      "title": null,
      "description": null,
      "reserved": null,
      "published": null,
      "modified": null,
      "withdrawn": null,
      "discovered": null,
      "released": null,
      "cwes": []
    },
    "advisory": {
      "uuid": "urn:uuid:a7d1d4fd-2c59-43c4-944e-92dbca7227e7",
      "identifier": "https://www.redhat.com/#CVE-2023-20862",
      "document_id": "CVE-2023-20862",
      "issuer": {
        "id": "d2241d75-31ca-4d25-8bf6-6eedafa16629",
        "name": "Red Hat Product Security",
        "cpe_key": null,
        "website": null
      },
      "published": "2023-04-19T00:00:00Z",
      "modified": "2023-11-14T22:09:12Z",
      "withdrawn": null,
      "title": "spring-security: Empty SecurityContext Is Not Properly Saved Upon Logout",
      "labels": {
        "type": "csaf",
        "source": "TrustifyContext"
      }
    },
    "scores": [
      {
        "type": "3.1",
        "value": 6.3,
        "severity": "medium"
      }
    ],
    "average_severity": "medium",
    "average_score": 6.3,
    "status": "affected",
    "context": {
      "cpe": "cpe:/a:redhat:jboss_fuse:6:*:*:*"
    },
    "version_range": {
      "version_scheme_id": "rpm",
      "low_version": "6.0.0",
      "low_inclusive": true,
      "high_version": "7.0.0",
      "high_inclusive": false
    },
    "remediations": [
      {
        "id": "9e1425e8-2502-55ce-9521-6d074cd2141d",
        "category": "no_fix_planned",
        "details": "Out of support scope",
        "url": null,
        "data": {
          "details": "Out of support scope",
          "category": "no_fix_planned",
          "product_ids": [
            "red_hat_jboss_fuse_6:spring-security"
          ]
        }
      }
    ]
  },
  {
    "vulnerability": {
      "normative": true,
      "identifier": "CVE-2023-20862",
      "title": null,
      "description": null,
      "reserved": null,
      "published": null,
      "modified": null,
      "withdrawn": null,
      "discovered": null,
      "released": null,
      "cwes": []
    },
    "advisory": {
      "uuid": "urn:uuid:a7d1d4fd-2c59-43c4-944e-92dbca7227e7",
      "identifier": "https://www.redhat.com/#CVE-2023-20862",
      "document_id": "CVE-2023-20862",
      "issuer": {
        "id": "d2241d75-31ca-4d25-8bf6-6eedafa16629",
        "name": "Red Hat Product Security",
        "cpe_key": null,
        "website": null
      },
      "published": "2023-04-19T00:00:00Z",
      "modified": "2023-11-14T22:09:12Z",
      "withdrawn": null,
      "title": "spring-security: Empty SecurityContext Is Not Properly Saved Upon Logout",
      "labels": {
        "type": "csaf",
        "source": "TrustifyContext"
      }
    },
    "scores": [
      {
        "type": "3.1",
        "value": 6.3,
        "severity": "medium"
      }
    ],
    "average_severity": "medium",
    "average_score": 6.3,
    "status": "affected",
    "context": {
      "cpe": "cpe:/a:redhat:jboss_enterprise_application_platform:6:*:*:*"
    },
    "version_range": {
      "version_scheme_id": "rpm",
      "low_version": "6.0.0",
      "low_inclusive": true,
      "high_version": "7.0.0",
      "high_inclusive": false
    },
    "remediations": [
      {
        "id": "9e1425e8-2502-55ce-9521-6d074cd2141d",
        "category": "no_fix_planned",
        "details": "Out of support scope",
        "url": null,
        "data": {
          "details": "Out of support scope",
          "category": "no_fix_planned",
          "product_ids": [
            "red_hat_jboss_enterprise_application_platform_6:spring-security"
          ]
        }
      }
    ]
  },
  {
    "vulnerability": {
      "normative": true,
      "identifier": "CVE-2023-20862",
      "title": null,
      "description": null,
      "reserved": null,
      "published": null,
      "modified": null,
      "withdrawn": null,
      "discovered": null,
      "released": null,
      "cwes": []
    },
    "advisory": {
      "uuid": "urn:uuid:a7d1d4fd-2c59-43c4-944e-92dbca7227e7",
      "identifier": "https://www.redhat.com/#CVE-2023-20862",
      "document_id": "CVE-2023-20862",
      "issuer": {
        "id": "d2241d75-31ca-4d25-8bf6-6eedafa16629",
        "name": "Red Hat Product Security",
        "cpe_key": null,
        "website": null
      },
      "published": "2023-04-19T00:00:00Z",
      "modified": "2023-11-14T22:09:12Z",
      "withdrawn": null,
      "title": "spring-security: Empty SecurityContext Is Not Properly Saved Upon Logout",
      "labels": {
        "type": "csaf",
        "source": "TrustifyContext"
      }
    },
    "scores": [
      {
        "type": "3.1",
        "value": 6.3,
        "severity": "medium"
      }
    ],
    "average_severity": "medium",
    "average_score": 6.3,
    "status": "affected",
    "context": {
      "cpe": "cpe:/a:redhat:jboss_fuse:7:*:*:*"
    },
    "version_range": {
      "version_scheme_id": "rpm",
      "low_version": "7.0.0",
      "low_inclusive": true,
      "high_version": "8.0.0",
      "high_inclusive": false
    },
    "remediations": [
      {
        "id": "9e1425e8-2502-55ce-9521-6d074cd2141d",
        "category": "no_fix_planned",
        "details": "Out of support scope",
        "url": null,
        "data": {
          "details": "Out of support scope",
          "category": "no_fix_planned",
          "product_ids": [
            "red_hat_jboss_fuse_7:spring-security"
          ]
        }
      }
    ]
  }
]
Output for vulnerability::service::test::analyze_purls_product_status_0044 test with PURL pkg:maven/io.quarkus/quarkus-vertx-http@1.0.0 and CSAF document csaf/cve-2023-0044.json
[
  {
    "vulnerability": {
      "normative": true,
      "identifier": "CVE-2023-0044",
      "title": null,
      "description": null,
      "reserved": null,
      "published": null,
      "modified": null,
      "withdrawn": null,
      "discovered": null,
      "released": null,
      "cwes": []
    },
    "advisory": {
      "uuid": "urn:uuid:1e95ada6-2949-417c-aa90-eb77697f767d",
      "identifier": "https://www.redhat.com/#CVE-2023-0044",
      "document_id": "CVE-2023-0044",
      "issuer": {
        "id": "ededa4af-eb82-4c2a-922e-fd7c88cdb2fd",
        "name": "Red Hat Product Security",
        "cpe_key": null,
        "website": null
      },
      "published": "2023-01-04T00:00:00Z",
      "modified": "2023-11-13T11:31:31Z",
      "withdrawn": null,
      "title": "quarkus-vertx-http: a cross-site attack may be initiated which might lead to the Information Disclosure",
      "labels": {
        "type": "csaf",
        "source": "TrustifyContext"
      }
    },
    "scores": [
      {
        "type": "3.1",
        "value": 5.3,
        "severity": "medium"
      }
    ],
    "average_severity": "medium",
    "average_score": 5.3,
    "status": "affected",
    "context": {
      "cpe": "cpe:/a:redhat:quarkus:2:*:*:*"
    },
    "version_range": {
      "version_scheme_id": "rpm",
      "low_version": "2.0.0",
      "low_inclusive": true,
      "high_version": "3.0.0",
      "high_inclusive": false
    },
    "remediations": [
      {
        "id": "3daf2756-58a7-5602-b507-75919330b5e9",
        "category": "workaround",
        "details": "This attack can be prevented with the Quarkus CSRF Prevention feature.",
        "url": null,
        "data": {
          "details": "This attack can be prevented with the Quarkus CSRF Prevention feature.",
          "category": "workaround",
          "product_ids": [
            "red_hat_build_of_quarkus:io.quarkus/quarkus-vertx-http"
          ]
        }
      },
      {
        "id": "d5b2e118-6766-5617-b2e7-d07a0d6642a1",
        "category": "none_available",
        "details": "Affected",
        "url": null,
        "data": {
          "details": "Affected",
          "category": "none_available",
          "product_ids": [
            "red_hat_build_of_quarkus:io.quarkus/quarkus-vertx-http"
          ]
        }
      }
    ]
  }
]

@ctron the product_ids section for each remediation should now be scoped to the vulnerability's context CPE for each remediation fetched via product statuses. Does the above two examples from the committed tests seem correct/reasonable to you?

@Strum355 Strum355 force-pushed the nsc/redhat-csaf-remediations branch from e95c6cc to e45e08e Compare March 23, 2026 17:53
@ctron
Copy link
Copy Markdown
Contributor

ctron commented Mar 24, 2026

I think they do. What feels a bit weird is the repetition of the vulnerability. Maybe I missed something, but wouldn't a reasonable model be:

vulnerabilities:
  - CVE-123:
      advisories:
        - ADV-123a:
            - context:
                - cpe1
                - cpe2
              remediations:
                 - […]
        - ADV-123b:
            […]

Also, where does the id of the remediation come from? And, does the product_ids field transport any meaningful information to the user?

@Strum355
Copy link
Copy Markdown
Member Author

What feels a bit weird is the repetition of the vulnerability. Maybe I missed something, but wouldn't a reasonable model be:

vulnerabilities:
  - CVE-123:
      advisories:
        - ADV-123a:
            - context:
                - cpe1
                - cpe2
              remediations:
                 - […]
        - ADV-123b:
            […]

I'm not personally opposed to this. Given that /api/v3/vulnerability/analyze has not been backported to a 0.4 release, we should be free to change the shape of the API surface. I would do that in a follow up PR though if you believe we should do this.

Also, where does the id of the remediation come from?

That is currently the database UUID. I'm not sure what the current trend is for trustify, whether we expose those or not (e.g. if clients want to deduplicate/group remediations they would need some unique ID for that). What are your thoughts?

And, does the product_ids field transport any meaningful information to the user?

I don't personally think its a meaningful identifier, unless we expose product branches elsewhere in the UI/API (I'm not familiar enough with trustify to know, and the product IDs arent particularly descriptive on their own), the data field moreso exists to expose fields that haven't been normalized in the schema such as of category, details and url that the CSAF schema includes (remediations spec link here). There are other fields that may be useful to include, but they may also be context dependent on the product IDs (entitlements and restart_required may differ per product), so I'm not sure how useful they would be either in isolation. Alternatively, we can drop the raw data field entirely, and only include the category, details and url fields for the time being. I don't feel qualified enough on the matter to choose one or the other personally, so what approach do you feel best about?

@ctron
Copy link
Copy Markdown
Contributor

ctron commented Mar 26, 2026

What feels a bit weird is the repetition of the vulnerability. Maybe I missed something, but wouldn't a reasonable model be:
[…]
I'm not personally opposed to this. Given that /api/v3/vulnerability/analyze has not been backported to a 0.4 release, we should be free to change the shape of the API surface. I would do that in a follow up PR though if you believe we should do this.

It feels like we don't have a good idea of the end goal/definition. But figuring it out on the way. Just merging things now, makes us committed to this. Maybe I'm just missing that definition. What's the motivation for merging this right now, rather than once we know what we want?

Also, where does the id of the remediation come from?

That is currently the database UUID. I'm not sure what the current trend is for trustify, whether we expose those or not (e.g. if clients want to deduplicate/group remediations they would need some unique ID for that). What are your thoughts?

So if it's an internal ID the user can work with (like requesting additional information) it might make sense. If it's just there because it was in the struct, I don't think it makes sense.

If the client would want to do that, why would it need that ID?

And, does the product_ids field transport any meaningful information to the user?

I don't personally think its a meaningful identifier, unless we expose product branches elsewhere in the UI/API (I'm not familiar enough with trustify to know, and the product IDs arent particularly descriptive on their own), the data field moreso exists to expose fields that haven't been normalized in the schema such as of category, details and url that the CSAF schema includes (remediations spec link here). There are other fields that may be useful to include, but they may also be context dependent on the product IDs (entitlements and restart_required may differ per product), so I'm not sure how useful they would be either in isolation. Alternatively, we can drop the raw data field entirely, and only include the category, details and url fields for the time being. I don't feel qualified enough on the matter to choose one or the other personally, so what approach do you feel best about?

Yea, I guess this is the problem, we just passing along a JSON blob that's only partially meaningful. On the other side, we are committing to this API. And this is basically some JSON fragment which only makes sense in the context of a CSAF 2.0 file.

I guess if we flag that data property in the OpenAPI spec as "not considered API" (not sure in which way) that we can just keep it and ignore that problem.

@Strum355
Copy link
Copy Markdown
Member Author

It feels like we don't have a good idea of the end goal/definition. But figuring it out on the way. Just merging things now, makes us committed to this. Maybe I'm just missing that definition. What's the motivation for merging this right now, rather than once we know what we want?

In terms of the API shape that this is in reply to, I don't personally agree with this take. The API shape is denoted in ADR 00010-version-range-in-responses by Dejan, which was signed off on by Ruben as the current main consumer of said endpoint (and that you also reviewed at the time). In my opinion, we can be flexible with the API shape as it isn't currently in a published release, so long it is usable by the exhort backend. The current shape works for exhort, but we are free to improve on it ahead of it being released if you feel as such. I would not include it as part of this pull request though, there is enough going on in this PR already (between the lengthy discussion and the changelist) and we should include Ruben in discussions around the API.

So if it's an internal ID the user can work with (like requesting additional information) it might make sense. If it's just there because it was in the struct, I don't think it makes sense.

Ill remove it from the API.

Yea, I guess this is the problem, we just passing along a JSON blob that's only partially meaningful. On the other side, we are committing to this API. And this is basically some JSON fragment which only makes sense in the context of a CSAF 2.0 file.

I guess if we flag that data property in the OpenAPI spec as "not considered API" (not sure in which way) that we can just keep it and ignore that problem.

The best we seem to be able to do with utoipa is mark it as deprecated, utoipa doesn't support field descriptions or anything else close enough. I'm not sure we're going to find a good solution in the short term, so for the time being I'm going to mark the field as ignored in the schema. We can revisit it at a later time if needed.

@ctron
Copy link
Copy Markdown
Contributor

ctron commented Mar 26, 2026

It feels like we don't have a good idea of the end goal/definition. But figuring it out on the way. Just merging things now, makes us committed to this. Maybe I'm just missing that definition. What's the motivation for merging this right now, rather than once we know what we want?

In terms of the API shape that this is in reply to, I don't personally agree with this take. The API shape is denoted in ADR 00010-version-range-in-responses by Dejan, which was signed off on by Ruben as the current main consumer of said endpoint (and that you also reviewed at the time). In my opinion, we can be flexible with the API shape as it isn't currently in a published release, so long it is usable by the exhort backend. The current shape works for exhort, but we are free to improve on it ahead of it being released if you feel as such. I would not include it as part of this pull request though, there is enough going on in this PR already (between the lengthy discussion and the changelist) and we should include Ruben in discussions around the API.

Right, thanks for referencing that. That ADR is about the addition of a version range. I did review it indeed, but also didn't approve (nor disaaprove it). Only made a remark of the version range struct. Also this ADR seems to have a different model, which makes more sense to me, and seems to differ from the one posted above:

  "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1?type=jar": [
    {
      "normative": true,
      "identifier": "CVE-2022-42003",
      "title": "In FasterXML jackson-databind before versions 2.13.4.1 and 2.12.17.1, resource exhaustion can occur because of a lack of a check in primitive value deserializers to avoid deep wrapper array nesting, when the UNWRAP_SINGLE_VALUE_ARRAYS feature is enabled.",
      "description": "In FasterXML jackson-databind before versions 2.13.4.1 and 2.12.17.1, resource exhaustion can occur because of a lack of a check in primitive value deserializers to avoid deep wrapper array nesting, when the UNWRAP_SINGLE_VALUE_ARRAYS feature is enabled.",
      "purl_statuses": [
        {
          "vulnerability": { ... },
          "status": "affected",
          "version_range": {
            "version_scheme_id": "semver",
            "low_version": "2.13.0",
            "low_inclusive": true,
            "high_version": "2.13.4.2",
            "high_inclusive": false
          }
        },
        {
          "vulnerability": { ... },
          "status": "fixed",
          "version_range": {
            "version_scheme_id": "semver",
            "low_version": "2.13.4.2",
            "low_inclusive": true,
            "high_version": null,
            "high_inclusive": false
          }
        }
      ]
    }
  ]

Anyway, I definitely have missed, that the PR actually doesn't change the model. That already happened before. Sorry for that. So let's ignore this. And yes, the example above then seems correct.

Yea, I guess this is the problem, we just passing along a JSON blob that's only partially meaningful. On the other side, we are committing to this API. And this is basically some JSON fragment which only makes sense in the context of a CSAF 2.0 file.
I guess if we flag that data property in the OpenAPI spec as "not considered API" (not sure in which way) that we can just keep it and ignore that problem.

The best we seem to be able to do with utoipa is mark it as deprecated, utoipa doesn't support field descriptions or anything else close enough. I'm not sure we're going to find a good solution in the short term, so for the time being I'm going to mark the field as ignored in the schema. We can revisit it at a later time if needed.

I think you can add descriptions with utoipa, we already do this:
image

Marking it as deprecated in addition might just do the trick.

@Strum355 Strum355 force-pushed the nsc/redhat-csaf-remediations branch from 57f02ad to 208cd09 Compare March 27, 2026 12:58
@Strum355
Copy link
Copy Markdown
Member Author

I think you can add descriptions with utoipa, we already do this: image

Marking it as deprecated in addition might just do the trick.

Youre absolutely right, I completely forgot that utoipa parses comments. Ive pushed a commit mark it deprecated with a comment stating its internal only/not for public use.

@Strum355 Strum355 force-pushed the nsc/redhat-csaf-remediations branch from 208cd09 to 8f40eaa Compare March 27, 2026 12:59
@ctron
Copy link
Copy Markdown
Contributor

ctron commented Mar 27, 2026

/scale-test

@github-actions
Copy link
Copy Markdown

🛠️ Scale test has started! Follow the progress here: Workflow Run

@github-actions
Copy link
Copy Markdown

Goose Report

Goose Attack Report

Plan Overview

Action Started Stopped Elapsed Users
Increasing 26-03-27 14:22:30 26-03-27 14:22:37 00:00:07 0 → 7
Maintaining 26-03-27 14:22:37 26-03-27 14:52:37 00:30:00 7
Decreasing 26-03-27 14:52:37 26-03-27 14:52:40 00:00:03 0 ← 7

Request Metrics

Method Name # Requests # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
GET download_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 (-10) 0 173.92 (-21.13) 27 (-17) 283 (-40) 0.03 (-0.01) 0.00 (+0.00)
GET get_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 (-10) 0 174.78 (+3.58) 81 (+58) 304 (+12) 0.03 (-0.01) 0.00 (+0.00)
GET get_advisory_by_doc_id 50 (-10) 0 30.90 (+4.32) 4 (+1) 157 (+38) 0.03 (-0.01) 0.00 (+0.00)
GET get_analysis_latest_cpe 50 (-10) 0 59.74 (-15.39) 7 (+3) 185 (-10) 0.03 (-0.01) 0.00 (+0.00)
GET get_analysis_status 50 (-10) 0 22.16 (+1.66) 2 (+1) 84 (+1) 0.03 (-0.01) 0.00 (+0.00)
GET get_purl_details[0000054a-a69b-5…520-80752db183e6] 50 (-10) 0 250.70 (-26.65) 70 (+31) 579 (-37) 0.03 (-0.01) 0.00 (+0.00)
GET get_sbom[sha256:a3442b37…3040057f79c70669] 50 (-10) 0 10786.14 (+1991.44) 407 (+123) 22641 (+8425) 0.03 (-0.01) 0.00 (+0.00)
GET get_sbom_license_ids[urn:uuid:019c4a…8ba-3cc0260ef778] 50 (-10) 0 28.58 (-8.74) 2 (0) 196 (+46) 0.03 (-0.01) 0.00 (+0.00)
GET list_advisory 50 (-10) 0 520.12 (-5.20) 172 (+12) 954 (-45) 0.03 (-0.01) 0.00 (+0.00)
GET list_advisory_labels 50 (-10) 0 14821.22 (+1401.49) 8501 (+4988) 22217 (+3239) 0.03 (-0.01) 0.00 (+0.00)
GET list_advisory_paginated 50 (-10) 0 433.90 (-29.73) 149 (+32) 912 (-404) 0.03 (-0.01) 0.00 (+0.00)
GET list_importer 51 (-9) 0 13.29 (-1.67) 2 (+1) 64 (-28) 0.03 (-0.01) 0.00 (+0.00)
GET list_organizations 50 (-10) 0 244.64 (+4.19) 87 (+38) 590 (+205) 0.03 (-0.01) 0.00 (+0.00)
GET list_packages 51 (-10) 0 421.76 (-53.43) 146 (+44) 905 (-184) 0.03 (-0.01) 0.00 (+0.00)
GET list_packages_paginated 51 (-10) 0 382.33 (-18.90) 143 (+40) 693 (-73) 0.03 (-0.01) 0.00 (+0.00)
GET list_products 55 (-10) 0 11.98 (-0.63) 5 (0) 39 (-13) 0.03 (-0.01) 0.00 (+0.00)
GET list_sboms 55 (-10) 0 116107.16 (+10964.21) 88795 (+11581) 161056 (+28813) 0.03 (-0.01) 0.00 (+0.00)
GET list_sboms_paginated 50 (-10) 0 961.84 (-141.18) 290 (-354) 2761 (-272) 0.03 (-0.01) 0.00 (+0.00)
GET list_vulnerabilities 51 (-9) 0 456.63 (-16.31) 142 (+54) 723 (-54) 0.03 (-0.01) 0.00 (+0.00)
GET list_vulnerabilities_paginated 51 (-9) 0 348.08 (-36.47) 89 (+6) 589 (-193) 0.03 (-0.01) 0.00 (+0.00)
GET sbom_by_package[pkg:oci/web-ter…-bundle&tag=1.11] 50 (-10) 0 175.24 (-35.24) 82 (+17) 304 (-191) 0.03 (-0.01) 0.00 (+0.00)
GET search_advisory 50 (-10) 0 1527.12 (-100.80) 181 (-10) 5917 (+885) 0.03 (-0.01) 0.00 (+0.00)
GET search_exact_purl 55 (-10) 0 153.11 (-41.52) 49 (-102) 277 (-126) 0.03 (-0.01) 0.00 (+0.00)
GET search_licenses 153 (+84) 0 36.46 (-6.74) 4 (-2) 185 (+7) 0.09 (+0.05) 0.00 (+0.00)
GET search_purls 55 (-10) 0 17756.95 (+9030.22) 14558 (+12663) 22630 (+6746) 0.03 (-0.01) 0.00 (+0.00)
GET search_purls_by_license 154 (+84) 0 11611.23 (-14124.82) 3882 (-1313) 33906 (-266095) 0.09 (+0.05) 0.00 (-0.00)
GET search_sboms_by_license 153 (+84) 0 44.70 (-9.01) 2 (-4) 336 (+62) 0.09 (+0.05) 0.00 (+0.00)
POST get_recommendations[pkg:maven/io.ne…8.1.redhat-00033] 50 (-10) 0 1358.96 (-25.69) 496 (-107) 1857 (-1037) 0.03 (-0.01) 0.00 (+0.00)
POST post_vulnerability_analyze[pkg:rpm/redhat/squid] 50 (-10) 0 5.82 (+0.32) 1 (0) 55 (+3) 0.03 (-0.01) 0.00 (+0.00)
Aggregated 1785 (-5) 0 6069.28 (-100.40) 1 (0) 161056 (-138945) 0.99 (-0.00) 0.00 (-0.00)

Response Time Metrics

Method Name 50%ile (ms) 60%ile (ms) 70%ile (ms) 80%ile (ms) 90%ile (ms) 95%ile (ms) 99%ile (ms) 100%ile (ms)
GET download_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 190 (-10) 200 (-20) 210 (-20) 220 (-40) 250 (-30) 270 (-30) 280 (-40) 280 (-40)
GET get_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 180 (-10) 190 (-10) 210 (0) 220 (-10) 260 (-10) 280 (+10) 300 (+10) 300 (+10)
GET get_advisory_by_doc_id 15 (-2) 24 (+2) 34 (+6) 64 (+16) 75 (+15) 83 (+14) 157 (+77) 157 (+38)
GET get_analysis_latest_cpe 56 (-22) 63 (-23) 75 (-21) 86 (-24) 120 (-20) 150 (-10) 185 (+15) 185 (-10)
GET get_analysis_status 8 (-4) 20 (+4) 26 (+7) 38 (+5) 59 (+6) 71 (0) 84 (+6) 84 (+1)
GET get_purl_details[0000054a-a69b-5…520-80752db183e6] 210 (-80) 250 (-60) 280 (-60) 320 (-60) 410 (0) 460 (-30) 579 (+79) 579 (-21)
GET get_sbom[sha256:a3442b37…3040057f79c70669] 13,000 (+2,000) 13,000 (+1,000) 13,000 (+1,000) 14,000 (+1,000) 14,000 (+1,000) 15,000 (+1,000) 22,641 (+8,641) 22,641 (+8,641)
GET get_sbom_license_ids[urn:uuid:019c4a…8ba-3cc0260ef778] 16 (-2) 19 (-9) 23 (-32) 42 (-22) 68 (-22) 100 (0) 196 (+86) 196 (+46)
GET list_advisory 500 (0) 500 (-100) 600 (0) 700 (+100) 700 (0) 800 (0) 954 (+54) 954 (-45)
GET list_advisory_labels 14,000 (0) 15,000 (+1,000) 15,000 (+1,000) 17,000 (+2,000) 19,000 (+2,000) 20,000 (+2,000) 22,000 (+3,022) 22,000 (+3,022)
GET list_advisory_paginated 430 (-50) 450 (-50) 480 (-20) 500 (-100) 600 (0) 600 (-100) 900 (-100) 900 (-100)
GET list_importer 5 (0) 7 (+1) 11 (+2) 17 (0) 45 (-11) 57 (-6) 59 (-7) 64 (-28)
GET list_organizations 240 (-30) 260 (-20) 270 (-10) 300 (+10) 360 (+10) 400 (+30) 590 (+220) 590 (+205)
GET list_packages 430 (-60) 480 (-20) 500 (-100) 500 (-100) 600 (-100) 700 (-100) 800 (-200) 900 (-100)
GET list_packages_paginated 390 (-30) 410 (-70) 490 (-10) 500 (0) 600 (0) 600 (0) 600 (0) 693 (-73)
GET list_products 10 (-1) 12 (0) 13 (0) 14 (0) 18 (-3) 22 (-1) 31 (-1) 39 (-13)
GET list_sboms 112,000 (+7,000) 118,000 (+8,000) 120,000 (0) 124,000 (+4,000) 127,000 (-5,000) 154,000 (+22,000) 161,000 (+29,000) 161,000 (+29,000)
GET list_sboms_paginated 1,000 (0) 1,000 (0) 1,000 (0) 1,000 (0) 1,000 (0) 2,000 (+1,000) 2,761 (-239) 2,761 (-239)
GET list_vulnerabilities 480 (-20) 600 (+100) 600 (0) 600 (0) 600 (0) 600 (0) 700 (0) 700 (-77)
GET list_vulnerabilities_paginated 380 (-40) 400 (-70) 420 (-60) 480 (-20) 500 (0) 589 (-11) 589 (-111) 589 (-193)
GET sbom_by_package[pkg:oci/web-ter…-bundle&tag=1.11] 180 (-20) 190 (-30) 200 (-40) 210 (-50) 230 (-170) 270 (-150) 300 (-180) 300 (-195)
GET search_advisory 700 (-300) 800 (-1,200) 2,000 (0) 3,000 (0) 4,000 (+1,000) 4,000 (+1,000) 5,917 (+1,917) 5,917 (+917)
GET search_exact_purl 150 (-20) 160 (-10) 170 (0) 170 (-40) 180 (-120) 210 (-180) 220 (-180) 277 (-123)
GET search_licenses 18 (-1) 29 (-7) 44 (-16) 62 (-16) 92 (-7) 110 (-20) 160 (0) 185 (+7)
GET search_purls 18,000 (+9,000) 18,000 (+9,000) 18,000 (+9,000) 18,000 (+8,000) 20,000 (+7,000) 21,000 (+8,000) 22,000 (+8,000) 22,630 (+6,746)
GET search_purls_by_license 11,000 (-3,000) 12,000 (-3,000) 14,000 (-2,000) 16,000 (-1,000) 18,000 (-14,000) 24,000 (-22,000) 32,000 (-252,000) 33,906 (-266,094)
GET search_sboms_by_license 22 (-11) 42 (+2) 60 (-5) 82 (-12) 100 (-40) 120 (-50) 180 (-10) 336 (+66)
POST get_recommendations[pkg:maven/io.ne…8.1.redhat-00033] 1,000 (0) 1,000 (0) 1,857 (-143) 1,857 (-143) 1,857 (-143) 1,857 (-143) 1,857 (-143) 1,857 (-1,037)
POST post_vulnerability_analyze[pkg:rpm/redhat/squid] 3 (0) 3 (-1) 3 (-3) 4 (-3) 8 (-3) 39 (+24) 55 (+38) 55 (+3)
Aggregated 210 (-60) 390 (-40) 600 (0) 4,000 (+2,000) 15,000 (+2,000) 18,000 (+1,000) 119,000 (-1,000) 161,000 (-139,000)

Status Code Metrics

Method Name Status Codes
GET download_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 [200]
GET get_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 [200]
GET get_advisory_by_doc_id 50 [200]
GET get_analysis_latest_cpe 50 [200]
GET get_analysis_status 50 [200]
GET get_purl_details[0000054a-a69b-5…520-80752db183e6] 50 [200]
GET get_sbom[sha256:a3442b37…3040057f79c70669] 50 [200]
GET get_sbom_license_ids[urn:uuid:019c4a…8ba-3cc0260ef778] 50 [200]
GET list_advisory 50 [200]
GET list_advisory_labels 50 [200]
GET list_advisory_paginated 50 [200]
GET list_importer 51 [200]
GET list_organizations 50 [200]
GET list_packages 51 [200]
GET list_packages_paginated 51 [200]
GET list_products 55 [200]
GET list_sboms 55 [200]
GET list_sboms_paginated 50 [200]
GET list_vulnerabilities 51 [200]
GET list_vulnerabilities_paginated 51 [200]
GET sbom_by_package[pkg:oci/web-ter…-bundle&tag=1.11] 50 [200]
GET search_advisory 50 [200]
GET search_exact_purl 55 [200]
GET search_licenses 153 [200]
GET search_purls 55 [200]
GET search_purls_by_license 154 [200]
GET search_sboms_by_license 153 [200]
POST get_recommendations[pkg:maven/io.ne…8.1.redhat-00033] 50 [200]
POST post_vulnerability_analyze[pkg:rpm/redhat/squid] 50 [200]
Aggregated 1,785 [200]

Transaction Metrics

Transaction # Times Run # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
WebsiteUser
0.0 logon 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.1 website_index 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.2 website_openapi 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.3 website_sboms 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.4 website_packages 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.5 website_advisories 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.6 website_importers 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
RestAPIUser
1.0 logon 50 (-10) 0 (0) 12.60 (-0.10) 8 (+2) 20 (-3) 0.03 (-0.01) 0.00 (+0.00)
1.1 list_organizations 50 (-10) 0 (0) 244.76 (+4.19) 87 (+38) 590 (+205) 0.03 (-0.01) 0.00 (+0.00)
1.2 list_advisory 50 (-10) 0 (0) 520.20 (-5.22) 172 (+12) 954 (-45) 0.03 (-0.01) 0.00 (+0.00)
1.3 list_advisory_paginated 50 (-10) 0 (0) 433.96 (-29.71) 149 (+32) 912 (-404) 0.03 (-0.01) 0.00 (+0.00)
1.4 get_advisory_by_doc_id 50 (-10) 0 (0) 31.02 (+4.40) 4 (+1) 157 (+37) 0.03 (-0.01) 0.00 (+0.00)
1.5 search_advisory 50 (-10) 0 (0) 1527.16 (-100.82) 181 (-10) 5917 (+885) 0.03 (-0.01) 0.00 (+0.00)
1.6 list_vulnerabilities 51 (-9) 0 (0) 456.67 (-16.33) 143 (+54) 723 (-54) 0.03 (-0.01) 0.00 (+0.00)
1.7 list_vulnerabilities_paginated 51 (-9) 0 (0) 348.10 (-36.52) 90 (+7) 589 (-193) 0.03 (-0.01) 0.00 (+0.00)
1.8 list_importer 51 (-9) 0 (0) 13.31 (-1.67) 2 (+1) 64 (-28) 0.03 (-0.01) 0.00 (+0.00)
1.9 list_packages 51 (-10) 0 (0) 421.80 (-53.46) 146 (+44) 905 (-184) 0.03 (-0.01) 0.00 (+0.00)
1.10 list_packages_paginated 51 (-10) 0 (0) 382.41 (-18.90) 143 (+40) 693 (-73) 0.03 (-0.01) 0.00 (+0.00)
1.11 search_purls 55 (-10) 0 (0) 17757.00 (+9030.25) 14558 (+12663) 22630 (+6746) 0.03 (-0.01) 0.00 (+0.00)
1.12 search_exact_purl 55 (-10) 0 (0) 153.18 (-41.50) 49 (-102) 277 (-126) 0.03 (-0.01) 0.00 (+0.00)
1.13 list_products 55 (-10) 0 (0) 12.02 (-0.66) 5 (-1) 39 (-13) 0.03 (-0.01) 0.00 (+0.00)
1.14 list_sboms 55 (-10) 0 (0) 116107.20 (+10964.17) 88795 (+11581) 161057 (+28814) 0.03 (-0.01) 0.00 (+0.00)
1.15 list_sboms_paginated 50 (-10) 0 (0) 961.90 (-141.18) 290 (-354) 2761 (-272) 0.03 (-0.01) 0.00 (+0.00)
1.16 get_analysis_status 50 (-10) 0 (0) 22.22 (+1.65) 2 (+1) 84 (+1) 0.03 (-0.01) 0.00 (+0.00)
1.17 get_analysis_latest_cpe 50 (-10) 0 (0) 59.80 (-15.40) 7 (+3) 185 (-10) 0.03 (-0.01) 0.00 (+0.00)
1.18 list_advisory_labels 50 (-10) 0 (0) 14821.24 (+1401.41) 8501 (+4988) 22217 (+3239) 0.03 (-0.01) 0.00 (+0.00)
1.19 get_sbom[sha256:a3442b37…3040057f79c70669] 50 (-10) 0 (0) 10786.22 (+1991.47) 407 (+123) 22641 (+8425) 0.03 (-0.01) 0.00 (+0.00)
1.20 sbom_by_package[pkg:oci/web-ter…-bundle&tag=1.11] 50 (-10) 0 (0) 175.28 (-35.34) 82 (+17) 304 (-191) 0.03 (-0.01) 0.00 (+0.00)
1.21 get_sbom_license_ids[urn:uuid:019c4a…8ba-3cc0260ef778] 50 (-10) 0 (0) 28.68 (-8.74) 2 (0) 196 (+46) 0.03 (-0.01) 0.00 (+0.00)
1.22 post_vulnerability_analyze[pkg:rpm/redhat/squid] 50 (-10) 0 (0) 5.88 (+0.33) 1 (0) 55 (+3) 0.03 (-0.01) 0.00 (+0.00)
1.23 get_purl_details[0000054a-a69b-5…520-80752db183e6] 50 (-10) 0 (0) 250.76 (-26.62) 70 (+31) 579 (-37) 0.03 (-0.01) 0.00 (+0.00)
1.24 get_recommendations[pkg:maven/io.ne…8.1.redhat-00033] 50 (-10) 0 (0) 1359.04 (-25.71) 496 (-107) 1857 (-1038) 0.03 (-0.01) 0.00 (+0.00)
1.25 download_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 (-10) 0 (0) 173.98 (-21.15) 27 (-17) 283 (-40) 0.03 (-0.01) 0.00 (+0.00)
1.26 get_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 (-10) 0 (0) 174.84 (+3.56) 81 (+58) 304 (+12) 0.03 (-0.01) 0.00 (+0.00)
RestAPIUserSlow
2.0 logon 153 (+84) 0 (0) 10.78 (-0.14) 6 (-1) 27 (+1) 0.09 (+0.05) 0.00 (+0.00)
2.1 search_licenses 153 (+84) 0 (0) 36.69 (-6.65) 4 (-2) 185 (+3) 0.09 (+0.05) 0.00 (+0.00)
2.2 search_sboms_by_license 153 (+84) 0 (0) 44.77 (-9.04) 2 (-4) 336 (+62) 0.09 (+0.05) 0.00 (+0.00)
2.3 search_purls_by_license 154 (+84) 0 (0) 11611.27 (-14124.86) 3882 (-1313) 33906 (-266095) 0.09 (+0.05) 0.00 (+0.00)
RestAPIUserDelete
3.0 logon 514 (+5) 0 (0) 10.84 (+0.14) 6 (0) 33 (-8) 0.29 (+0.00) 0.00 (+0.00)
RestAdvisoryLableUser
4.0 logon 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
Aggregated 2502 (+74) 0 (0) 4330.00 (-218.49) 1 (0) 161057 (-138944) 1.39 (+0.04) 0.00 (+0.00)

Scenario Metrics

Transaction # Users # Times Run Average (ms) Min (ms) Max (ms) Scenarios/s Iterations
WebsiteUser 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
RestAPIUser 5 (0) 50 (-10) 167937.48 (+25023.03) 133866 (+31672) 218902 (+40088) 0.03 (-0.01) 10.00 (-2.00)
RestAPIUserSlow 1 (0) 153 (+84) 11682.48 (-14338.99) 3931 (-1301) 34125 (-266041) 0.09 (+0.05) 153.00 (+84.00)
RestAPIUserDelete 1 (0) 514 (+5) 3504.34 (-37.91) 3019 (+3) 4019 (+1) 0.29 (+0.00) 514.00 (+5.00)
RestAdvisoryLableUser 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
Aggregated 7 (0) 717 (+79) 16716.21 (-2364.28) 3019 (+3) 218902 (-81264) 0.40 (+0.04) 677.00 (+87.00)

📄 Full Report (Go to "Artifacts" and download report)

@Strum355
Copy link
Copy Markdown
Member Author

Goose Report

Goose Attack Report

Plan Overview

Action Started Stopped Elapsed Users
Increasing 26-03-27 14:22:30 26-03-27 14:22:37 00:00:07 0 → 7
Maintaining 26-03-27 14:22:37 26-03-27 14:52:37 00:30:00 7
Decreasing 26-03-27 14:52:37 26-03-27 14:52:40 00:00:03 0 ← 7

Request Metrics

Method Name # Requests # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
GET download_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 (-10) 0 173.92 (-21.13) 27 (-17) 283 (-40) 0.03 (-0.01) 0.00 (+0.00)
GET get_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 (-10) 0 174.78 (+3.58) 81 (+58) 304 (+12) 0.03 (-0.01) 0.00 (+0.00)
GET get_advisory_by_doc_id 50 (-10) 0 30.90 (+4.32) 4 (+1) 157 (+38) 0.03 (-0.01) 0.00 (+0.00)
GET get_analysis_latest_cpe 50 (-10) 0 59.74 (-15.39) 7 (+3) 185 (-10) 0.03 (-0.01) 0.00 (+0.00)
GET get_analysis_status 50 (-10) 0 22.16 (+1.66) 2 (+1) 84 (+1) 0.03 (-0.01) 0.00 (+0.00)
GET get_purl_details[0000054a-a69b-5…520-80752db183e6] 50 (-10) 0 250.70 (-26.65) 70 (+31) 579 (-37) 0.03 (-0.01) 0.00 (+0.00)
GET get_sbom[sha256:a3442b37…3040057f79c70669] 50 (-10) 0 10786.14 (+1991.44) 407 (+123) 22641 (+8425) 0.03 (-0.01) 0.00 (+0.00)
GET get_sbom_license_ids[urn:uuid:019c4a…8ba-3cc0260ef778] 50 (-10) 0 28.58 (-8.74) 2 (0) 196 (+46) 0.03 (-0.01) 0.00 (+0.00)
GET list_advisory 50 (-10) 0 520.12 (-5.20) 172 (+12) 954 (-45) 0.03 (-0.01) 0.00 (+0.00)
GET list_advisory_labels 50 (-10) 0 14821.22 (+1401.49) 8501 (+4988) 22217 (+3239) 0.03 (-0.01) 0.00 (+0.00)
GET list_advisory_paginated 50 (-10) 0 433.90 (-29.73) 149 (+32) 912 (-404) 0.03 (-0.01) 0.00 (+0.00)
GET list_importer 51 (-9) 0 13.29 (-1.67) 2 (+1) 64 (-28) 0.03 (-0.01) 0.00 (+0.00)
GET list_organizations 50 (-10) 0 244.64 (+4.19) 87 (+38) 590 (+205) 0.03 (-0.01) 0.00 (+0.00)
GET list_packages 51 (-10) 0 421.76 (-53.43) 146 (+44) 905 (-184) 0.03 (-0.01) 0.00 (+0.00)
GET list_packages_paginated 51 (-10) 0 382.33 (-18.90) 143 (+40) 693 (-73) 0.03 (-0.01) 0.00 (+0.00)
GET list_products 55 (-10) 0 11.98 (-0.63) 5 (0) 39 (-13) 0.03 (-0.01) 0.00 (+0.00)
GET list_sboms 55 (-10) 0 116107.16 (+10964.21) 88795 (+11581) 161056 (+28813) 0.03 (-0.01) 0.00 (+0.00)
GET list_sboms_paginated 50 (-10) 0 961.84 (-141.18) 290 (-354) 2761 (-272) 0.03 (-0.01) 0.00 (+0.00)
GET list_vulnerabilities 51 (-9) 0 456.63 (-16.31) 142 (+54) 723 (-54) 0.03 (-0.01) 0.00 (+0.00)
GET list_vulnerabilities_paginated 51 (-9) 0 348.08 (-36.47) 89 (+6) 589 (-193) 0.03 (-0.01) 0.00 (+0.00)
GET sbom_by_package[pkg:oci/web-ter…-bundle&tag=1.11] 50 (-10) 0 175.24 (-35.24) 82 (+17) 304 (-191) 0.03 (-0.01) 0.00 (+0.00)
GET search_advisory 50 (-10) 0 1527.12 (-100.80) 181 (-10) 5917 (+885) 0.03 (-0.01) 0.00 (+0.00)
GET search_exact_purl 55 (-10) 0 153.11 (-41.52) 49 (-102) 277 (-126) 0.03 (-0.01) 0.00 (+0.00)
GET search_licenses 153 (+84) 0 36.46 (-6.74) 4 (-2) 185 (+7) 0.09 (+0.05) 0.00 (+0.00)
GET search_purls 55 (-10) 0 17756.95 (+9030.22) 14558 (+12663) 22630 (+6746) 0.03 (-0.01) 0.00 (+0.00)
GET search_purls_by_license 154 (+84) 0 11611.23 (-14124.82) 3882 (-1313) 33906 (-266095) 0.09 (+0.05) 0.00 (-0.00)
GET search_sboms_by_license 153 (+84) 0 44.70 (-9.01) 2 (-4) 336 (+62) 0.09 (+0.05) 0.00 (+0.00)
POST get_recommendations[pkg:maven/io.ne…8.1.redhat-00033] 50 (-10) 0 1358.96 (-25.69) 496 (-107) 1857 (-1037) 0.03 (-0.01) 0.00 (+0.00)
POST post_vulnerability_analyze[pkg:rpm/redhat/squid] 50 (-10) 0 5.82 (+0.32) 1 (0) 55 (+3) 0.03 (-0.01) 0.00 (+0.00)
Aggregated 1785 (-5) 0 6069.28 (-100.40) 1 (0) 161056 (-138945) 0.99 (-0.00) 0.00 (-0.00)

Response Time Metrics

Method Name 50%ile (ms) 60%ile (ms) 70%ile (ms) 80%ile (ms) 90%ile (ms) 95%ile (ms) 99%ile (ms) 100%ile (ms)
GET download_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 190 (-10) 200 (-20) 210 (-20) 220 (-40) 250 (-30) 270 (-30) 280 (-40) 280 (-40)
GET get_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 180 (-10) 190 (-10) 210 (0) 220 (-10) 260 (-10) 280 (+10) 300 (+10) 300 (+10)
GET get_advisory_by_doc_id 15 (-2) 24 (+2) 34 (+6) 64 (+16) 75 (+15) 83 (+14) 157 (+77) 157 (+38)
GET get_analysis_latest_cpe 56 (-22) 63 (-23) 75 (-21) 86 (-24) 120 (-20) 150 (-10) 185 (+15) 185 (-10)
GET get_analysis_status 8 (-4) 20 (+4) 26 (+7) 38 (+5) 59 (+6) 71 (0) 84 (+6) 84 (+1)
GET get_purl_details[0000054a-a69b-5…520-80752db183e6] 210 (-80) 250 (-60) 280 (-60) 320 (-60) 410 (0) 460 (-30) 579 (+79) 579 (-21)
GET get_sbom[sha256:a3442b37…3040057f79c70669] 13,000 (+2,000) 13,000 (+1,000) 13,000 (+1,000) 14,000 (+1,000) 14,000 (+1,000) 15,000 (+1,000) 22,641 (+8,641) 22,641 (+8,641)
GET get_sbom_license_ids[urn:uuid:019c4a…8ba-3cc0260ef778] 16 (-2) 19 (-9) 23 (-32) 42 (-22) 68 (-22) 100 (0) 196 (+86) 196 (+46)
GET list_advisory 500 (0) 500 (-100) 600 (0) 700 (+100) 700 (0) 800 (0) 954 (+54) 954 (-45)
GET list_advisory_labels 14,000 (0) 15,000 (+1,000) 15,000 (+1,000) 17,000 (+2,000) 19,000 (+2,000) 20,000 (+2,000) 22,000 (+3,022) 22,000 (+3,022)
GET list_advisory_paginated 430 (-50) 450 (-50) 480 (-20) 500 (-100) 600 (0) 600 (-100) 900 (-100) 900 (-100)
GET list_importer 5 (0) 7 (+1) 11 (+2) 17 (0) 45 (-11) 57 (-6) 59 (-7) 64 (-28)
GET list_organizations 240 (-30) 260 (-20) 270 (-10) 300 (+10) 360 (+10) 400 (+30) 590 (+220) 590 (+205)
GET list_packages 430 (-60) 480 (-20) 500 (-100) 500 (-100) 600 (-100) 700 (-100) 800 (-200) 900 (-100)
GET list_packages_paginated 390 (-30) 410 (-70) 490 (-10) 500 (0) 600 (0) 600 (0) 600 (0) 693 (-73)
GET list_products 10 (-1) 12 (0) 13 (0) 14 (0) 18 (-3) 22 (-1) 31 (-1) 39 (-13)
GET list_sboms 112,000 (+7,000) 118,000 (+8,000) 120,000 (0) 124,000 (+4,000) 127,000 (-5,000) 154,000 (+22,000) 161,000 (+29,000) 161,000 (+29,000)
GET list_sboms_paginated 1,000 (0) 1,000 (0) 1,000 (0) 1,000 (0) 1,000 (0) 2,000 (+1,000) 2,761 (-239) 2,761 (-239)
GET list_vulnerabilities 480 (-20) 600 (+100) 600 (0) 600 (0) 600 (0) 600 (0) 700 (0) 700 (-77)
GET list_vulnerabilities_paginated 380 (-40) 400 (-70) 420 (-60) 480 (-20) 500 (0) 589 (-11) 589 (-111) 589 (-193)
GET sbom_by_package[pkg:oci/web-ter…-bundle&tag=1.11] 180 (-20) 190 (-30) 200 (-40) 210 (-50) 230 (-170) 270 (-150) 300 (-180) 300 (-195)
GET search_advisory 700 (-300) 800 (-1,200) 2,000 (0) 3,000 (0) 4,000 (+1,000) 4,000 (+1,000) 5,917 (+1,917) 5,917 (+917)
GET search_exact_purl 150 (-20) 160 (-10) 170 (0) 170 (-40) 180 (-120) 210 (-180) 220 (-180) 277 (-123)
GET search_licenses 18 (-1) 29 (-7) 44 (-16) 62 (-16) 92 (-7) 110 (-20) 160 (0) 185 (+7)
GET search_purls 18,000 (+9,000) 18,000 (+9,000) 18,000 (+9,000) 18,000 (+8,000) 20,000 (+7,000) 21,000 (+8,000) 22,000 (+8,000) 22,630 (+6,746)
GET search_purls_by_license 11,000 (-3,000) 12,000 (-3,000) 14,000 (-2,000) 16,000 (-1,000) 18,000 (-14,000) 24,000 (-22,000) 32,000 (-252,000) 33,906 (-266,094)
GET search_sboms_by_license 22 (-11) 42 (+2) 60 (-5) 82 (-12) 100 (-40) 120 (-50) 180 (-10) 336 (+66)
POST get_recommendations[pkg:maven/io.ne…8.1.redhat-00033] 1,000 (0) 1,000 (0) 1,857 (-143) 1,857 (-143) 1,857 (-143) 1,857 (-143) 1,857 (-143) 1,857 (-1,037)
POST post_vulnerability_analyze[pkg:rpm/redhat/squid] 3 (0) 3 (-1) 3 (-3) 4 (-3) 8 (-3) 39 (+24) 55 (+38) 55 (+3)
Aggregated 210 (-60) 390 (-40) 600 (0) 4,000 (+2,000) 15,000 (+2,000) 18,000 (+1,000) 119,000 (-1,000) 161,000 (-139,000)

Status Code Metrics

Method Name Status Codes
GET download_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 [200]
GET get_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 [200]
GET get_advisory_by_doc_id 50 [200]
GET get_analysis_latest_cpe 50 [200]
GET get_analysis_status 50 [200]
GET get_purl_details[0000054a-a69b-5…520-80752db183e6] 50 [200]
GET get_sbom[sha256:a3442b37…3040057f79c70669] 50 [200]
GET get_sbom_license_ids[urn:uuid:019c4a…8ba-3cc0260ef778] 50 [200]
GET list_advisory 50 [200]
GET list_advisory_labels 50 [200]
GET list_advisory_paginated 50 [200]
GET list_importer 51 [200]
GET list_organizations 50 [200]
GET list_packages 51 [200]
GET list_packages_paginated 51 [200]
GET list_products 55 [200]
GET list_sboms 55 [200]
GET list_sboms_paginated 50 [200]
GET list_vulnerabilities 51 [200]
GET list_vulnerabilities_paginated 51 [200]
GET sbom_by_package[pkg:oci/web-ter…-bundle&tag=1.11] 50 [200]
GET search_advisory 50 [200]
GET search_exact_purl 55 [200]
GET search_licenses 153 [200]
GET search_purls 55 [200]
GET search_purls_by_license 154 [200]
GET search_sboms_by_license 153 [200]
POST get_recommendations[pkg:maven/io.ne…8.1.redhat-00033] 50 [200]
POST post_vulnerability_analyze[pkg:rpm/redhat/squid] 50 [200]
Aggregated 1,785 [200]

Transaction Metrics

Transaction # Times Run # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
WebsiteUser
0.0 logon 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.1 website_index 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.2 website_openapi 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.3 website_sboms 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.4 website_packages 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.5 website_advisories 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
0.6 website_importers 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
RestAPIUser
1.0 logon 50 (-10) 0 (0) 12.60 (-0.10) 8 (+2) 20 (-3) 0.03 (-0.01) 0.00 (+0.00)
1.1 list_organizations 50 (-10) 0 (0) 244.76 (+4.19) 87 (+38) 590 (+205) 0.03 (-0.01) 0.00 (+0.00)
1.2 list_advisory 50 (-10) 0 (0) 520.20 (-5.22) 172 (+12) 954 (-45) 0.03 (-0.01) 0.00 (+0.00)
1.3 list_advisory_paginated 50 (-10) 0 (0) 433.96 (-29.71) 149 (+32) 912 (-404) 0.03 (-0.01) 0.00 (+0.00)
1.4 get_advisory_by_doc_id 50 (-10) 0 (0) 31.02 (+4.40) 4 (+1) 157 (+37) 0.03 (-0.01) 0.00 (+0.00)
1.5 search_advisory 50 (-10) 0 (0) 1527.16 (-100.82) 181 (-10) 5917 (+885) 0.03 (-0.01) 0.00 (+0.00)
1.6 list_vulnerabilities 51 (-9) 0 (0) 456.67 (-16.33) 143 (+54) 723 (-54) 0.03 (-0.01) 0.00 (+0.00)
1.7 list_vulnerabilities_paginated 51 (-9) 0 (0) 348.10 (-36.52) 90 (+7) 589 (-193) 0.03 (-0.01) 0.00 (+0.00)
1.8 list_importer 51 (-9) 0 (0) 13.31 (-1.67) 2 (+1) 64 (-28) 0.03 (-0.01) 0.00 (+0.00)
1.9 list_packages 51 (-10) 0 (0) 421.80 (-53.46) 146 (+44) 905 (-184) 0.03 (-0.01) 0.00 (+0.00)
1.10 list_packages_paginated 51 (-10) 0 (0) 382.41 (-18.90) 143 (+40) 693 (-73) 0.03 (-0.01) 0.00 (+0.00)
1.11 search_purls 55 (-10) 0 (0) 17757.00 (+9030.25) 14558 (+12663) 22630 (+6746) 0.03 (-0.01) 0.00 (+0.00)
1.12 search_exact_purl 55 (-10) 0 (0) 153.18 (-41.50) 49 (-102) 277 (-126) 0.03 (-0.01) 0.00 (+0.00)
1.13 list_products 55 (-10) 0 (0) 12.02 (-0.66) 5 (-1) 39 (-13) 0.03 (-0.01) 0.00 (+0.00)
1.14 list_sboms 55 (-10) 0 (0) 116107.20 (+10964.17) 88795 (+11581) 161057 (+28814) 0.03 (-0.01) 0.00 (+0.00)
1.15 list_sboms_paginated 50 (-10) 0 (0) 961.90 (-141.18) 290 (-354) 2761 (-272) 0.03 (-0.01) 0.00 (+0.00)
1.16 get_analysis_status 50 (-10) 0 (0) 22.22 (+1.65) 2 (+1) 84 (+1) 0.03 (-0.01) 0.00 (+0.00)
1.17 get_analysis_latest_cpe 50 (-10) 0 (0) 59.80 (-15.40) 7 (+3) 185 (-10) 0.03 (-0.01) 0.00 (+0.00)
1.18 list_advisory_labels 50 (-10) 0 (0) 14821.24 (+1401.41) 8501 (+4988) 22217 (+3239) 0.03 (-0.01) 0.00 (+0.00)
1.19 get_sbom[sha256:a3442b37…3040057f79c70669] 50 (-10) 0 (0) 10786.22 (+1991.47) 407 (+123) 22641 (+8425) 0.03 (-0.01) 0.00 (+0.00)
1.20 sbom_by_package[pkg:oci/web-ter…-bundle&tag=1.11] 50 (-10) 0 (0) 175.28 (-35.34) 82 (+17) 304 (-191) 0.03 (-0.01) 0.00 (+0.00)
1.21 get_sbom_license_ids[urn:uuid:019c4a…8ba-3cc0260ef778] 50 (-10) 0 (0) 28.68 (-8.74) 2 (0) 196 (+46) 0.03 (-0.01) 0.00 (+0.00)
1.22 post_vulnerability_analyze[pkg:rpm/redhat/squid] 50 (-10) 0 (0) 5.88 (+0.33) 1 (0) 55 (+3) 0.03 (-0.01) 0.00 (+0.00)
1.23 get_purl_details[0000054a-a69b-5…520-80752db183e6] 50 (-10) 0 (0) 250.76 (-26.62) 70 (+31) 579 (-37) 0.03 (-0.01) 0.00 (+0.00)
1.24 get_recommendations[pkg:maven/io.ne…8.1.redhat-00033] 50 (-10) 0 (0) 1359.04 (-25.71) 496 (-107) 1857 (-1038) 0.03 (-0.01) 0.00 (+0.00)
1.25 download_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 (-10) 0 (0) 173.98 (-21.15) 27 (-17) 283 (-40) 0.03 (-0.01) 0.00 (+0.00)
1.26 get_advisory[5b25cdef-428a-4…29e-fbb3415c22ab] 50 (-10) 0 (0) 174.84 (+3.56) 81 (+58) 304 (+12) 0.03 (-0.01) 0.00 (+0.00)
RestAPIUserSlow
2.0 logon 153 (+84) 0 (0) 10.78 (-0.14) 6 (-1) 27 (+1) 0.09 (+0.05) 0.00 (+0.00)
2.1 search_licenses 153 (+84) 0 (0) 36.69 (-6.65) 4 (-2) 185 (+3) 0.09 (+0.05) 0.00 (+0.00)
2.2 search_sboms_by_license 153 (+84) 0 (0) 44.77 (-9.04) 2 (-4) 336 (+62) 0.09 (+0.05) 0.00 (+0.00)
2.3 search_purls_by_license 154 (+84) 0 (0) 11611.27 (-14124.86) 3882 (-1313) 33906 (-266095) 0.09 (+0.05) 0.00 (+0.00)
RestAPIUserDelete
3.0 logon 514 (+5) 0 (0) 10.84 (+0.14) 6 (0) 33 (-8) 0.29 (+0.00) 0.00 (+0.00)
RestAdvisoryLableUser
4.0 logon 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
Aggregated 2502 (+74) 0 (0) 4330.00 (-218.49) 1 (0) 161057 (-138944) 1.39 (+0.04) 0.00 (+0.00)

Scenario Metrics

Transaction # Users # Times Run Average (ms) Min (ms) Max (ms) Scenarios/s Iterations
WebsiteUser 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
RestAPIUser 5 (0) 50 (-10) 167937.48 (+25023.03) 133866 (+31672) 218902 (+40088) 0.03 (-0.01) 10.00 (-2.00)
RestAPIUserSlow 1 (0) 153 (+84) 11682.48 (-14338.99) 3931 (-1301) 34125 (-266041) 0.09 (+0.05) 153.00 (+84.00)
RestAPIUserDelete 1 (0) 514 (+5) 3504.34 (-37.91) 3019 (+3) 4019 (+1) 0.29 (+0.00) 514.00 (+5.00)
RestAdvisoryLableUser 0 (0) 0 (0) 0.00 (+0.00) 0 (0) 0 (0) 0.00 (+0.00) 0.00 (+0.00)
Aggregated 7 (0) 717 (+79) 16716.21 (-2364.28) 3019 (+3) 218902 (-81264) 0.40 (+0.04) 677.00 (+87.00)

📄 Full Report (Go to "Artifacts" and download report)

Looks like theres almost no impact to the affected endpoints from these test runs. Are we good to merge?

@ctron ctron added this pull request to the merge queue Mar 30, 2026
Merged via the queue into guacsec:main with commit f839bb4 Mar 30, 2026
6 checks passed
@github-project-automation github-project-automation Bot moved this to Done in Trustify Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants