Skip to content

Conversation

mrizzi
Copy link
Collaborator

@mrizzi mrizzi commented Sep 26, 2025

This PR implements license filtering functionality for the SBOM service and refactors duplicate code patterns between SBOM and PURL services to improve maintainability.

Changes

  1. Added License Filtering to SBOM Service: Implemented the same two-phase license filtering approach used in PURL service
  2. Code Refactoring and Deduplication: within modules/fundamental/src/ moved to common module common/license_filtering.rs some functions from purl/service/mod.rs to be reused in sbom/service/sbom.rs

Relates to TC-2832

Assisted-by: Claude Code

Summary by Sourcery

Implement two-phase (SPDX and CycloneDX) license filtering for the SBOM service and refactor duplicate license filtering logic into a shared module for both SBOM and PURL services.

New Features:

  • Enable SBOM service to filter by license using the same two-phase SPDX/CycloneDX approach as the PURL service.

Enhancements:

  • Move common license filtering functions into a new shared module and update PURL and SBOM services to use the centralized apply_license_filtering API.

Tests:

  • Add comprehensive SBOM service tests for license filtering covering exact matches, partial matches, OR operations, pagination, combined filters, and negative cases.

Summary by Sourcery

Add license filtering support to the SBOM service and refactor duplicate SPDX/CycloneDX license filtering code into a shared module for both SBOM and PURL services

New Features:

  • Enable SBOM service to filter SBOMs by license using a two-phase SPDX and CycloneDX approach

Enhancements:

  • Extract shared license filtering logic into a new common/license_filtering module and update PURL and SBOM services to use apply_license_filtering

Tests:

  • Add comprehensive SBOM tests for license filtering covering exact matches, partial matches, OR operations, pagination, combined filters, and negative cases

…ces (TC-2832)

Signed-off-by: mrizzi <mrizzi@redhat.com>
Assisted-by: Claude Code
@mrizzi mrizzi requested review from ctron and bxf12315 September 26, 2025 15:41
Copy link
Contributor

sourcery-ai bot commented Sep 26, 2025

Reviewer's Guide

This PR centralizes the two-phase SPDX/CycloneDX license filtering logic into a new shared module and applies it to both the SBOM and PURL services, removing duplication and extending license-based filtering and its tests for SBOM.

Sequence diagram for license filtering in SBOM and PURL services

sequenceDiagram
    participant Client
    participant Service
    participant LicenseFiltering
    participant Database
    Client->>Service: Request with license filter
    Service->>LicenseFiltering: apply_license_filtering(main_query, search_query, ...)
    LicenseFiltering->>Database: Query SPDX licenses
    LicenseFiltering->>Database: Query CycloneDX licenses
    LicenseFiltering->>Service: Return filtered query
    Service->>Database: Execute filtered query
    Service->>Client: Return filtered results
Loading

File-Level Changes

Change Details Files
Extract duplicate license filtering logic into a shared module
  • Create common/license_filtering.rs with build_spdx, build_cyclonedx, base query, and apply_license_filtering
  • Expose LICENSE constant and refactor common functions
  • Update common/mod.rs to include the new license_filtering module
modules/fundamental/src/common/license_filtering.rs
modules/fundamental/src/common/mod.rs
Refactor PURL service to use shared apply_license_filtering
  • Remove inline build_spdx/build_cyclonedx and create_license_filtering_base_query methods
  • Replace manual subquery union logic with a call to apply_license_filtering
  • Adjust imports and remove unused sea_query/ExpandLicenseExpression references
modules/fundamental/src/purl/service/mod.rs
Integrate license filtering into SBOM service
  • Invoke apply_license_filtering in SbomService.fetch_sboms
  • Handle LICENSE field translation to no-op in main query where filtering is offloaded
  • Import new filtering utilities
modules/fundamental/src/sbom/service/sbom.rs
Add comprehensive SBOM service tests for license filtering
  • Implement fetch_sboms_filter_by_license with scenarios for exact, partial, OR, and combined filters
  • Cover negative, pagination, and integration with other filters
  • Assert expected total counts and SBOM names
modules/fundamental/src/sbom/service/test.rs

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
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 there - I've reviewed your changes - here's some feedback:

  • Consider adding integration tests for PurlService license filtering similar to the SBOM tests to ensure the new common apply_license_filtering logic works across both services.
  • The special‐case translator in SbomService that maps the LICENSE field to an empty string feels hacky—consider handling license filtering more uniformly in apply_license_filtering or its helpers instead of requiring a fallback in the query translator.
  • common/service.rs is becoming quite large; extracting the license‐filtering helpers into their own module could improve readability and make future maintenance easier.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider adding integration tests for PurlService license filtering similar to the SBOM tests to ensure the new common apply_license_filtering logic works across both services.
- The special‐case translator in SbomService that maps the LICENSE field to an empty string feels hacky—consider handling license filtering more uniformly in apply_license_filtering or its helpers instead of requiring a fallback in the query translator.
- common/service.rs is becoming quite large; extracting the license‐filtering helpers into their own module could improve readability and make future maintenance easier.

## Individual Comments

### Comment 1
<location> `modules/fundamental/src/common/service.rs:145-147` </location>
<code_context>
+        .map(|constraint| q(&format!("{constraint}")))
+    {
+        let license_filtering_base_query = base_query_fn();
+        let mut select_from_spdx =
+            build_spdx_license_query(license_query.clone(), license_filtering_base_query.clone())?;
+        let select_from_cyclonedx =
+            build_cyclonedx_license_query(license_query, license_filtering_base_query)?;
+
</code_context>

<issue_to_address>
**nitpick:** Avoid unnecessary cloning of license_filtering_base_query.

If cloning is necessary due to mutability, please add a clarifying comment. Otherwise, consider reusing the base query to avoid redundancy.
</issue_to_address>

### Comment 2
<location> `modules/fundamental/src/sbom/service/test.rs:255-264` </location>
<code_context>
+    assert_eq!(results.total, 2);
+    assert_eq!(results.items.len(), 2);
+
+    // Test 5: Negative test - license that doesn't exist
+    let results = service
+        .fetch_sboms(
+            q("license=NONEXISTENT_LICENSE"),
+            Paginated::default(),
+            (),
+            &ctx.db,
+        )
+        .await?;
+
+    log::debug!("Nonexistent license filter results: {results:#?}");
+    // Should return no SBOMs
+    assert_eq!(results.total, 0);
+    assert!(results.items.is_empty());
+
+    // Test 6: Empty license query
</code_context>

<issue_to_address>
**suggestion (testing):** Add a test for invalid license query syntax.

Consider adding a test case for invalid license query syntax to ensure the service handles malformed queries gracefully without crashing.
</issue_to_address>

### Comment 3
<location> `modules/fundamental/src/sbom/service/test.rs:299-318` </location>
<code_context>
+        "quay/quay-builder-qemu-rhcos-rhel8"
+    );
+
+    // Test 8: Pagination with license filtering
+    let results = service
+        .fetch_sboms(
+            q("license~GPL"),
+            Paginated {
+                offset: 0,
+                limit: 1,
+            },
+            (),
+            &ctx.db,
+        )
+        .await?;
+
+    log::debug!("Paginated license filter results: {results:#?}");
+    // Should return at most 1 item but show total count
+    // Both SBOMs contain GPL licenses, but limit to 1
+    assert_eq!(results.items.len(), 1);
+    assert_eq!(results.total, 2);
+
+    // Test 9: Verify that SBOMs without license filters still work
</code_context>

<issue_to_address>
**suggestion (testing):** Add a test for pagination with offset > 0.

Please include a test case with offset > 0 to ensure correct pagination behavior when skipping items with license filtering.

```suggestion
    // Test 8: Pagination with license filtering
    let results = service
        .fetch_sboms(
            q("license~GPL"),
            Paginated {
                offset: 0,
                limit: 1,
            },
            (),
            &ctx.db,
        )
        .await?;

    log::debug!("Paginated license filter results: {results:#?}");
    // Should return at most 1 item but show total count
    // Both SBOMs contain GPL licenses, but limit to 1
    assert_eq!(results.items.len(), 1);
    assert_eq!(results.total, 2);

    // Test 8b: Pagination with license filtering and offset > 0
    let results_offset = service
        .fetch_sboms(
            q("license~GPL"),
            Paginated {
                offset: 1,
                limit: 1,
            },
            (),
            &ctx.db,
        )
        .await?;

    log::debug!("Paginated license filter results with offset: {results_offset:#?}");
    // Should return the second item (if order is deterministic), and total should still be 2
    assert_eq!(results_offset.items.len(), 1);
    assert_eq!(results_offset.total, 2);

    // Optionally, check that the returned SBOM is different from the first one
    // (Uncomment if order is deterministic and you want to check identity)
    // assert_ne!(results.items[0].head.name, results_offset.items[0].head.name);

    // Test 9: Verify that SBOMs without license filters still work
```
</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.

Copy link

codecov bot commented Sep 26, 2025

Codecov Report

❌ Patch coverage is 95.04950% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.06%. Comparing base (89bf882) to head (bcaaa32).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
...odules/fundamental/src/common/license_filtering.rs 95.65% 2 Missing and 2 partials ⚠️
modules/fundamental/src/sbom/service/sbom.rs 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1995      +/-   ##
==========================================
+ Coverage   68.00%   68.06%   +0.06%     
==========================================
  Files         355      356       +1     
  Lines       19807    19857      +50     
  Branches    19807    19857      +50     
==========================================
+ Hits        13470    13516      +46     
- Misses       5557     5560       +3     
- Partials      780      781       +1     

☔ 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.

Signed-off-by: mrizzi <mrizzi@redhat.com>
Signed-off-by: mrizzi <mrizzi@redhat.com>
@mrizzi mrizzi force-pushed the sbom-filter-by-license branch from 1f30027 to bcaaa32 Compare September 26, 2025 16:44
@mrizzi
Copy link
Collaborator Author

mrizzi commented Sep 26, 2025

@sourcery-ai review

Copy link
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 there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `modules/fundamental/src/sbom/service/sbom.rs:164-150` </location>
<code_context>
                     .translator(|f, op, v| match f.split_once(':') {
                         Some(("label", key)) => Some(format!("labels:{key}{op}{v}")),
-                        _ => None,
+                        _ => match f {
+                            // Add an empty condition (effectively TRUE) to the main SQL query
+                            // since the real filtering by license happens in the license subqueries above
+                            LICENSE => Some("".to_string()),
+                            _ => None,
+                        },
                     }),
</code_context>

<issue_to_address>
**nitpick:** Empty condition for license field may affect query clarity.

Consider returning None or adding a clarifying comment to make the handling of the LICENSE field more explicit and reduce potential confusion for future maintainers.
</issue_to_address>

### Comment 2
<location> `modules/fundamental/src/common/license_filtering.rs:120-40` </location>
<code_context>
+pub fn apply_license_filtering<E, BE, F, C>(
</code_context>

<issue_to_address>
**suggestion:** Generic license filtering function increases flexibility but adds complexity.

Document the expected types and usage patterns to assist future maintainers.
</issue_to_address>

### Comment 3
<location> `modules/fundamental/src/sbom/service/test.rs:270-268` </location>
<code_context>
+    assert_eq!(results.total, 0);
+    assert!(results.items.is_empty());
+
+    // Test 6: Empty license query
+    let results = service
+        .fetch_sboms(q("license="), Paginated::default(), (), &ctx.db)
+        .await?;
+
+    log::debug!("Empty license query results: {results:#?}");
+    // Should return no SBOMs or handle gracefully
+    assert_eq!(results.total, 0);
+    assert!(results.items.is_empty());
+
+    // Test 7: Combine license filter with other filters (should work together)
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding a test for a malformed or invalid license query.

Adding a test for malformed license queries, such as `license==GPL` or `license~`, will verify that the service responds appropriately and avoids unexpected behavior.
</issue_to_address>

### Comment 4
<location> `modules/fundamental/src/sbom/service/test.rs:322-331` </location>
<code_context>
+    );
+    assert_eq!(results.total, 2);
+
+    // Test 8b: Pagination with license filtering and offset > 0
+    let results_offset = service
+        .fetch_sboms(
+            q("license~GPL").sort("name:desc"),
+            Paginated {
+                offset: 1,
+                limit: 1,
+            },
+            (),
+            &ctx.db,
+        )
+        .await?;
+    log::debug!("Paginated license filter results with offset: {results_offset:#?}");
+    // Should return the second item and total should still be 2
+    assert_eq!(results_offset.items.len(), 1);
+    assert_eq!(results_offset.items[0].head.name, "MTV-2.6");
+    assert_eq!(results_offset.total, 2);
+
+    // Test 9: Verify that SBOMs without license filters still work
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding a test for pagination with a limit of zero.

This will verify that the service returns no items but reports the correct total count when the limit is zero.
</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.

query,
&search,
create_sbom_license_filtering_base_query,
sbom::Column::SbomId,
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick: Empty condition for license field may affect query clarity.

Consider returning None or adding a clarifying comment to make the handling of the LICENSE field more explicit and reduce potential confusion for future maintainers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

can you better explain?

Copy link
Contributor

Choose a reason for hiding this comment

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

Certainly! My nitpick refers to how the LICENSE field is handled in the query translator function (the closure passed to .translator() in your query construction). When a license filter is present, the actual filtering is performed by the subqueries created in apply_license_filtering, not by the main query itself.

Currently, when the LICENSE field is encountered in the translator, it returns an empty string (effectively a TRUE condition), which means the main query doesn't filter by license directly. This can be confusing for future maintainers because it looks like the LICENSE field is ignored or mishandled.

Why clarify?

  • It helps future readers understand that license filtering is handled in a separate, dedicated subquery, not in the main query.
  • It prevents misunderstandings or accidental changes that could break the intended filtering logic.

How to clarify?

  • Add a comment in the translator closure explaining why LICENSE returns an empty condition.
  • Alternatively, you could return None for LICENSE, but then ensure that the license filtering is always handled by the subquery logic and not missed.

Example comment:

translator(|f, op, v| match f {
    // LICENSE filtering is handled by the license subquery in apply_license_filtering
    LICENSE => Some("".to_string()), // No-op: main query does not filter by license directly
    _ => None,
})

This makes the intent clear and helps maintainers understand the separation of concerns in the filtering logic.

}),
)?
.into_query())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Generic license filtering function increases flexibility but adds complexity.

Document the expected types and usage patterns to assist future maintainers.

Copy link
Contributor

@bxf12315 bxf12315 left a comment

Choose a reason for hiding this comment

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

Thanks a lot!

@mrizzi
Copy link
Collaborator Author

mrizzi commented Sep 29, 2025

/scale-test

Copy link

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

@mrizzi mrizzi added the backport release/0.4.z Backport (0.4.z) label Sep 29, 2025
Copy link

Goose Report

Goose Attack Report

Plan Overview

Action Started Stopped Elapsed Users
Increasing 25-09-29 15:26:35 25-09-29 15:26:40 00:00:05 0 → 5
Maintaining 25-09-29 15:26:40 25-09-29 15:31:40 00:05:00 5
Decreasing 25-09-29 15:31:40 25-09-29 15:31:40 00:00:00 0 ← 5

Request Metrics

Method Name # Requests # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
GET get_advisory_by_doc_id 75 (-40) 0 10.35 (-1.84) 3 (0) 57 (-3) 0.25 (-0.13) 0.00 (+0.00)
GET get_analysis_latest_cpe 80 (-38) 0 120.39 (-5.15) 34 (+1) 278 (-31) 0.27 (-0.13) 0.00 (+0.00)
GET get_analysis_status 80 (-38) 0 7.32 (+1.76) 1 (0) 55 (+3) 0.27 (-0.13) 0.00 (+0.00)
GET get_purl_details[b00df2ca-df21-5…874-304e9c54e2bd] 80 (-37) 0 739.96 (-296.05) 353 (+103) 1137 (-427) 0.27 (-0.12) 0.00 (+0.00)
GET get_purl_gc 80 (-38) 80 1.16 (-0.26) 1 (0) 4 (-1) 0.27 (-0.13) 0.27 (-0.13)
GET get_sbom[sha256:720e4451…a939656247164447] 80 (-38) 0 779.47 (-522.64) 200 (-13) 1905 (-1589) 0.27 (-0.13) 0.00 (+0.00)
GET get_sbom_license_ids[urn:uuid:019731…104-331632a21144] 80 (-37) 0 770.28 (-136.90) 419 (+136) 1086 (-336) 0.27 (-0.12) 0.00 (+0.00)
GET list_advisory 79 (-37) 0 512.49 (+65.06) 294 (+169) 860 (-128) 0.26 (-0.12) 0.00 (+0.00)
GET list_advisory_paginated 75 (-41) 0 405.67 (+53.62) 223 (+121) 548 (+18) 0.25 (-0.14) 0.00 (+0.00)
GET list_importer 75 (-39) 0 5.65 (+2.64) 1 (0) 55 (+8) 0.25 (-0.13) 0.00 (+0.00)
GET list_organizations 79 (-37) 0 8.25 (-2.77) 1 (0) 52 (+1) 0.26 (-0.12) 0.00 (+0.00)
GET list_packages 75 (-39) 0 490.24 (+134.47) 133 (+44) 890 (+56) 0.25 (-0.13) 0.00 (+0.00)
GET list_packages_paginated 75 (-39) 0 398.05 (+67.43) 126 (+28) 681 (+119) 0.25 (-0.13) 0.00 (+0.00)
GET list_products 80 (-39) 0 6.56 (-5.19) 4 (+2) 20 (-47) 0.27 (-0.13) 0.00 (+0.00)
GET list_sboms 80 (-39) 0 1105.46 (-181.60) 532 (-68) 1569 (-420) 0.27 (-0.13) 0.00 (+0.00)
GET list_sboms_paginated 80 (-39) 0 1419.26 (-1450.08) 448 (-51) 3273 (-4799) 0.27 (-0.13) 0.00 (+0.00)
GET list_vulnerabilities 75 (-40) 0 233.49 (+3.82) 80 (+25) 380 (+16) 0.25 (-0.13) 0.00 (+0.00)
GET list_vulnerabilities_paginated 75 (-39) 0 184.64 (+12.46) 110 (+69) 344 (+55) 0.25 (-0.13) 0.00 (+0.00)
GET sbom_by_package[pkg:maven/io.qu…dhat.com%2fga%2f] 80 (-37) 0 52.45 (-8.05) 9 (-1) 170 (-23) 0.27 (-0.12) 0.00 (+0.00)
GET search_advisory 75 (-40) 0 990.39 (+212.72) 308 (+172) 1829 (-283) 0.25 (-0.13) 0.00 (+0.00)
GET search_exact_purl 80 (-39) 0 6.22 (-3.56) 2 (0) 11 (-52) 0.27 (-0.13) 0.00 (+0.00)
GET search_purls 80 (-39) 0 10313.50 (+8493.46) 5009 (+4406) 12799 (+7500) 0.27 (-0.13) 0.00 (+0.00)
POST post_vulnerability_analyze[pkg:rpm/redhat/…h=noarch&epoch=1] 80 (-37) 0 502.45 (-208.09) 235 (+13) 915 (-184) 0.27 (-0.12) 0.00 (+0.00)
Aggregated 1798 (-886) 80 840.37 (+277.74) 1 (0) 12799 (+4727) 5.99 (-2.95) 0.27 (-0.13)

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 get_advisory_by_doc_id 6 (0) 6 (-1) 8 (-1) 10 (-1) 19 (-27) 49 (-4) 54 (-2) 57 (-3)
GET get_analysis_latest_cpe 99 (-11) 110 (-10) 120 (-30) 190 (+20) 200 (+10) 210 (+10) 260 (-20) 278 (-31)
GET get_analysis_status 2 (-1) 3 (0) 4 (0) 5 (+1) 9 (+3) 50 (+4) 53 (+2) 55 (+3)
GET get_purl_details[b00df2ca-df21-5…874-304e9c54e2bd] 800 (-200) 800 (-200) 800 (-200) 900 (-100) 900 (-100) 1,000 (0) 1,000 (0) 1,000 (-564)
GET get_purl_gc 1 (0) 1 (0) 1 (0) 1 (-1) 2 (-1) 2 (-2) 3 (-1) 4 (-1)
GET get_sbom[sha256:720e4451…a939656247164447] 600 (+170) 600 (+100) 800 (-2,200) 1,000 (-2,000) 1,905 (-1,095) 1,905 (-1,095) 1,905 (-1,095) 1,905 (-1,095)
GET get_sbom_license_ids[urn:uuid:019731…104-331632a21144] 800 (-100) 800 (-100) 900 (-100) 900 (-100) 1,000 (0) 1,000 (0) 1,000 (0) 1,000 (0)
GET list_advisory 490 (+40) 500 (+20) 500 (0) 600 (+100) 600 (0) 700 (0) 800 (+100) 860 (-128)
GET list_advisory_paginated 410 (+40) 420 (+40) 440 (+40) 470 (+60) 490 (+30) 500 (+20) 500 (0) 500 (0)
GET list_importer 2 (0) 3 (+1) 4 (+1) 5 (+1) 8 (+3) 24 (+17) 45 (+35) 55 (+8)
GET list_organizations 4 (0) 5 (0) 7 (+1) 9 (-2) 21 (-20) 33 (-13) 45 (-4) 52 (+1)
GET list_packages 460 (+90) 480 (+100) 490 (+100) 600 (+190) 700 (+210) 800 (+300) 890 (+290) 890 (+90)
GET list_packages_paginated 410 (+90) 420 (+70) 420 (+40) 470 (+80) 500 (+80) 500 (+40) 600 (+100) 681 (+119)
GET list_products 6 (0) 6 (-1) 7 (-1) 7 (-3) 9 (-37) 14 (-39) 19 (-40) 20 (-47)
GET list_sboms 1,000 (0) 1,000 (0) 1,000 (0) 1,000 (-989) 1,000 (-989) 1,000 (-989) 1,000 (-989) 1,569 (-420)
GET list_sboms_paginated 1,000 (-1,000) 1,000 (-2,000) 2,000 (-2,000) 2,000 (-2,000) 2,000 (-3,000) 2,000 (-4,000) 3,000 (-4,000) 3,000 (-5,000)
GET list_vulnerabilities 240 (+20) 240 (-10) 250 (-20) 270 (-10) 290 (0) 300 (0) 370 (+10) 380 (+20)
GET list_vulnerabilities_paginated 180 (0) 190 (0) 200 (0) 210 (0) 250 (+30) 260 (0) 300 (+11) 340 (+51)
GET sbom_by_package[pkg:maven/io.qu…dhat.com%2fga%2f] 41 (-17) 59 (-10) 69 (-6) 80 (-13) 100 (-10) 120 (-40) 160 (-30) 170 (-20)
GET search_advisory 1,000 (+300) 1,000 (+300) 1,000 (+100) 1,829 (+829) 1,829 (+829) 1,829 (-171) 1,829 (-171) 1,829 (-171)
GET search_exact_purl 6 (+1) 6 (0) 7 (0) 7 (-1) 8 (-9) 9 (-42) 10 (-47) 11 (-52)
GET search_purls 12,000 (+11,000) 12,000 (+11,000) 12,000 (+10,000) 12,000 (+8,000) 12,799 (+8,799) 12,799 (+7,799) 12,799 (+7,799) 12,799 (+7,799)
POST post_vulnerability_analyze[pkg:rpm/redhat/…h=noarch&epoch=1] 440 (-260) 500 (-300) 600 (-200) 700 (-200) 800 (-100) 800 (-200) 900 (-100) 900 (-100)
Aggregated 310 (+30) 430 (+40) 600 (0) 800 (-100) 1,000 (0) 2,000 (0) 12,000 (+7,000) 12,799 (+4,799)

Status Code Metrics

Method Name Status Codes
GET get_advisory_by_doc_id 75 [200]
GET get_analysis_latest_cpe 80 [200]
GET get_analysis_status 80 [200]
GET get_purl_details[b00df2ca-df21-5…874-304e9c54e2bd] 80 [200]
GET get_purl_gc 80 [400]
GET get_sbom[sha256:720e4451…a939656247164447] 80 [200]
GET get_sbom_license_ids[urn:uuid:019731…104-331632a21144] 80 [200]
GET list_advisory 79 [200]
GET list_advisory_paginated 75 [200]
GET list_importer 75 [200]
GET list_organizations 79 [200]
GET list_packages 75 [200]
GET list_packages_paginated 75 [200]
GET list_products 80 [200]
GET list_sboms 80 [200]
GET list_sboms_paginated 80 [200]
GET list_vulnerabilities 75 [200]
GET list_vulnerabilities_paginated 75 [200]
GET sbom_by_package[pkg:maven/io.qu…dhat.com%2fga%2f] 80 [200]
GET search_advisory 75 [200]
GET search_exact_purl 80 [200]
GET search_purls 80 [200]
POST post_vulnerability_analyze[pkg:rpm/redhat/…h=noarch&epoch=1] 80 [200]
Aggregated 1,718 [200], 80 [400]

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 79 (-37) 0 (0) 16.00 (+1.29) 8 (+1) 32 (-5) 0.26 (-0.12) 0.00 (+0.00)
1.1 list_organizations 79 (-37) 0 (0) 8.57 (-2.63) 1 (0) 55 (+4) 0.26 (-0.12) 0.00 (+0.00)
1.2 list_advisory 79 (-37) 0 (0) 512.53 (+65.04) 294 (+169) 860 (-128) 0.26 (-0.12) 0.00 (+0.00)
1.3 list_advisory_paginated 75 (-41) 0 (0) 405.75 (+53.62) 223 (+121) 548 (+18) 0.25 (-0.14) 0.00 (+0.00)
1.4 get_advisory_by_doc_id 75 (-40) 0 (0) 10.41 (-1.89) 3 (0) 57 (-3) 0.25 (-0.13) 0.00 (+0.00)
1.5 search_advisory 75 (-40) 0 (0) 990.41 (+212.68) 308 (+172) 1829 (-283) 0.25 (-0.13) 0.00 (+0.00)
1.6 list_vulnerabilities 75 (-40) 0 (0) 233.63 (+3.85) 81 (+26) 380 (+16) 0.25 (-0.13) 0.00 (+0.00)
1.7 list_vulnerabilities_paginated 75 (-39) 0 (0) 184.67 (+12.41) 110 (+69) 344 (+55) 0.25 (-0.13) 0.00 (+0.00)
1.8 list_importer 75 (-39) 0 (0) 5.68 (+2.61) 1 (0) 55 (+8) 0.25 (-0.13) 0.00 (+0.00)
1.9 list_packages 75 (-39) 0 (0) 490.36 (+134.51) 133 (+44) 890 (+56) 0.25 (-0.13) 0.00 (+0.00)
1.10 list_packages_paginated 75 (-39) 0 (0) 398.17 (+67.51) 126 (+28) 682 (+120) 0.25 (-0.13) 0.00 (+0.00)
1.11 search_purls 80 (-39) 0 (0) 10313.55 (+8493.47) 5009 (+4406) 12800 (+7501) 0.27 (-0.13) 0.00 (+0.00)
1.12 search_exact_purl 80 (-39) 0 (0) 6.26 (-3.55) 2 (0) 11 (-52) 0.27 (-0.13) 0.00 (+0.00)
1.13 list_products 80 (-39) 0 (0) 6.59 (-5.22) 4 (+2) 20 (-47) 0.27 (-0.13) 0.00 (+0.00)
1.14 list_sboms 80 (-39) 0 (0) 1105.51 (-181.62) 532 (-68) 1569 (-420) 0.27 (-0.13) 0.00 (+0.00)
1.15 list_sboms_paginated 80 (-39) 0 (0) 1419.35 (-1450.03) 448 (-51) 3273 (-4799) 0.27 (-0.13) 0.00 (+0.00)
1.16 get_analysis_status 80 (-38) 0 (0) 7.35 (+1.71) 1 (0) 55 (+3) 0.27 (-0.13) 0.00 (+0.00)
1.17 get_analysis_latest_cpe 80 (-38) 0 (0) 120.47 (-5.14) 34 (+1) 278 (-31) 0.27 (-0.13) 0.00 (+0.00)
1.18 get_purl_gc 80 (-38) 0 (0) 1.21 (-0.27) 1 (0) 4 (-1) 0.27 (-0.13) 0.00 (+0.00)
1.19 get_sbom[sha256:720e4451…a939656247164447] 80 (-38) 0 (0) 779.54 (-522.69) 200 (-13) 1905 (-1590) 0.27 (-0.13) 0.00 (+0.00)
1.20 sbom_by_package[pkg:maven/io.qu…dhat.com%2fga%2f] 80 (-37) 0 (0) 52.47 (-8.10) 9 (-1) 170 (-23) 0.27 (-0.12) 0.00 (+0.00)
1.21 get_sbom_license_ids[urn:uuid:019731…104-331632a21144] 80 (-37) 0 (0) 770.33 (-136.91) 419 (+136) 1086 (-336) 0.27 (-0.12) 0.00 (+0.00)
1.22 post_vulnerability_analyze[pkg:rpm/redhat/…h=noarch&epoch=1] 80 (-37) 0 (0) 502.51 (-208.15) 235 (+13) 915 (-185) 0.27 (-0.12) 0.00 (+0.00)
1.23 get_purl_details[b00df2ca-df21-5…874-304e9c54e2bd] 80 (-37) 0 (0) 740.05 (-296.04) 353 (+103) 1137 (-427) 0.27 (-0.12) 0.00 (+0.00)
Aggregated 1877 (-923) 0 (0) 805.00 (+265.68) 1 (0) 12800 (+4728) 6.26 (-3.08) 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) 79 (-37) 18904.67 (+6116.14) 9471 (+3043) 23652 (+2954) 0.26 (-0.12) 15.80 (-7.40)
Aggregated 5 (0) 79 (-37) 18904.67 (+6116.14) 9471 (+3043) 23652 (+2954) 0.26 (-0.12) 15.80 (-7.40)

Error Metrics

Method Name # Error
GET get_purl_gc 80 400 Bad Request: get_purl_gc

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

@mrizzi mrizzi added this pull request to the merge queue Sep 30, 2025
Merged via the queue into guacsec:main with commit acb4650 Sep 30, 2025
6 of 7 checks passed
@mrizzi mrizzi deleted the sbom-filter-by-license branch September 30, 2025 08:23
@trustify-ci-bot
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport release/0.4.z Backport (0.4.z)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants