Skip to content

Conversation

@dejanb
Copy link
Contributor

@dejanb dejanb commented Dec 10, 2025

Propose ingesting CSAF remediation guidance and exposing it via APIs. Remediations provide actionable guidance (upgrade paths, workarounds) alongside vulnerability status information.

Assisted-by: Claude

Summary by Sourcery

Documentation:

  • Add ADR 00011 describing schema, ingestion flow, and API changes to support CSAF remediation guidance linked to vulnerability status records.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 10, 2025

Reviewer's Guide

Adds a new architecture decision record (ADR 00011) defining how CSAF remediation guidance will be modeled, stored, ingested, and exposed via existing status APIs, including schema, ingestion flow, and query patterns.

Sequence diagram for CSAF remediation ingestion flow

sequenceDiagram
    participant CsafIngestion as CsafIngestionService
    participant StatusCreator as StatusCreator
    participant ResolveCache as ResolveProductIdCache
    participant RemediationCreator as RemediationCreator
    participant DB as Database

    CsafIngestion->>StatusCreator: create_status_records(csaf_document)
    StatusCreator->>ResolveCache: resolve_product_ids(csaf_product_ids)
    ResolveCache-->>StatusCreator: product_id_to_status_mapping
    StatusCreator->>DB: insert_purl_status_records()
    StatusCreator->>DB: insert_product_status_records()
    StatusCreator-->>CsafIngestion: status_creation_result_with_mapping

    CsafIngestion->>RemediationCreator: create_remediations(csaf_remediations, mapping)
    RemediationCreator->>DB: insert_into_remediation(advisory_id, vulnerability_id, category, details, url, data)
    RemediationCreator->>DB: insert_into_remediation_purl_status(remediation_id, purl_status_ids)
    RemediationCreator->>DB: insert_into_remediation_product_status(remediation_id, product_status_ids)
    RemediationCreator-->>CsafIngestion: remediation_creation_result
Loading

Sequence diagram for API status query with remediations

sequenceDiagram
    actor Client
    participant Api as StatusApiService
    participant DB as Database

    Client->>Api: GET /v2/purl/{key}
    Api->>DB: SELECT purl_status_with_remediations(purl_key)
    DB-->>Api: purl_status_rows_with_joined_remediations
    Api->>Api: map_rows_to_PurlStatus_and_RemediationSummary
    Api-->>Client: PurlDetails_with_status_and_remediations

    Client->>Api: POST /v3/vulnerability/analyze
    Api->>DB: query_analysis_status_with_remediations(sbom_or_purls)
    DB-->>Api: analysis_rows_with_remediations
    Api->>Api: build_AnalysisResponse_with_PurlStatus_and_RemediationSummary
    Api-->>Client: AnalysisResponse
Loading

ER diagram for CSAF remediation schema additions

erDiagram
    advisory_vulnerability {
        UUID advisory_id
        VARCHAR vulnerability_id
    }

    remediation {
        UUID id
        UUID advisory_id
        VARCHAR vulnerability_id
        VARCHAR category
        TEXT details
        VARCHAR url
        JSONB data
    }

    purl_status {
        UUID id
        %% existing_columns
        TEXT existing_columns
    }

    product_status {
        UUID id
        %% existing_columns
        TEXT existing_columns
    }

    remediation_purl_status {
        UUID remediation_id
        UUID purl_status_id
    }

    remediation_product_status {
        UUID remediation_id
        UUID product_status_id
    }

    advisory_vulnerability ||--o{ remediation : has_remediation

    remediation ||--o{ remediation_purl_status : links_purl_status
    purl_status ||--o{ remediation_purl_status : is_target_of

    remediation ||--o{ remediation_product_status : links_product_status
    product_status ||--o{ remediation_product_status : is_target_of
Loading

Class diagram for remediation API models and status aggregation

classDiagram
    class RemediationSummary {
        Uuid id
        String category
        Option~String~ details
        Option~String~ url
        Option~JsonValue~ data
    }

    class PurlStatus {
        /* existing_fields */
        String status
        String vulnerability_id
        List~RemediationSummary~ remediations
    }

    class SbomStatus {
        /* existing_fields */
        String status
        String vulnerability_id
        List~RemediationSummary~ remediations
    }

    class PurlDetails {
        /* existing_fields */
        List~PurlStatus~ statuses
    }

    class SbomAdvisory {
        /* existing_fields */
        List~SbomStatus~ statuses
    }

    class AnalysisResponse {
        /* existing_fields */
        List~PurlStatus~ purl_statuses
    }

    PurlStatus "1" --> "*" RemediationSummary : has
    SbomStatus "1" --> "*" RemediationSummary : has

    PurlDetails "1" --> "*" PurlStatus : includes
    SbomAdvisory "1" --> "*" SbomStatus : includes
    AnalysisResponse "1" --> "*" PurlStatus : includes
Loading

File-Level Changes

Change Details Files
Document schema and relational model for storing CSAF remediation guidance and linking it to existing status records.
  • Introduce a remediation table keyed by advisory and vulnerability with category, details, URL, and JSONB metadata fields.
  • Define junction tables to associate remediations with purl_status and product_status records using composite primary keys and cascade deletes.
  • Specify indexes on advisory/vulnerability and status foreign keys to keep remediation lookups efficient.
docs/adrs/00011-csaf-remediation.md
Describe ingestion flow changes needed to create remediation records and link them to resolved product status entries.
  • Extend the ingestion design so StatusCreator tracks created status records per CSAF product_id.
  • Introduce a RemediationCreator component concept that uses the product_id-to-status mapping and existing ResolveProductIdCache to populate remediation and junction tables.
docs/adrs/00011-csaf-remediation.md
Define API surface and query patterns for exposing remediations alongside vulnerability status responses.
  • Add a RemediationSummary API model containing basic remediation fields and optional JSONB metadata.
  • Augment PurlStatus and SbomStatus response models to include a list of associated remediations, and enumerate affected endpoints.
  • Specify SQL join patterns using LEFT JOIN from status tables to remediation junction tables to retrieve remediations with minimal impact on queries without remediations.
docs/adrs/00011-csaf-remediation.md

Possibly linked issues

  • #(unknown): PR provides the ADR that defines CSAF remediation extraction and API exposure requested by the issue, partially fulfilling it.

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:

  • In the 'Related ADRs' and 'References' sections the Markdown link syntax is inverted, e.g. (ADR 00008)[00008-purls-recommendation.md]; update these to [ADR 00008](00008-purls-recommendation.md) and similarly for the CSAF test data path so the links render correctly.
  • Consider clarifying in the ADR how conflicting or overlapping remediations will be handled when multiple advisories reference the same vulnerability/package pair (e.g., prioritization or deduplication rules), since the schema allows multiple remediation records to attach to the same status.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the 'Related ADRs' and 'References' sections the Markdown link syntax is inverted, e.g. `(ADR 00008)[00008-purls-recommendation.md]`; update these to `[ADR 00008](00008-purls-recommendation.md)` and similarly for the CSAF test data path so the links render correctly.
- Consider clarifying in the ADR how conflicting or overlapping remediations will be handled when multiple advisories reference the same vulnerability/package pair (e.g., prioritization or deduplication rules), since the schema allows multiple remediation records to attach to the same status.

## Individual Comments

### Comment 1
<location> `docs/adrs/00011-csaf-remediation.md:93` </location>
<code_context>
+### Design Choices
+
+- Remediations link to **specific purl_status/product_status records**
+- Keep statuses (category) as VARCHAR. Having separate statuses table have added more complexity to queries than benefits.
+- Normalize only important remediation fields, while keeping the rest in JSON blob
+
</code_context>

<issue_to_address>
**suggestion (typo):** Fix subject–verb agreement in the explanation about a separate statuses table.

The sentence is grammatically off. Consider: "Having a separate statuses table would have added more complexity to queries than benefits" or "Having a separate statuses table has added more complexity to queries than benefits," depending on the tense you want.

```suggestion
- Remediations link to **specific purl_status/product_status records**
- Keep statuses (category) as VARCHAR. Having a separate statuses table has added more complexity to queries than benefits.
```
</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.

Propose ingesting CSAF remediation guidance and exposing it via APIs.
Remediations provide actionable guidance (upgrade paths, workarounds)
alongside vulnerability status information.

Assisted-by: Claude
Signed-off-by: Dejan Bosanac <[email protected]>
@dejanb dejanb requested a review from ctron December 10, 2025 15:59
@codecov
Copy link

codecov bot commented Dec 10, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.23%. Comparing base (3d9314c) to head (e3960a2).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2179   +/-   ##
=======================================
  Coverage   68.22%   68.23%           
=======================================
  Files         376      376           
  Lines       21190    21190           
  Branches    21190    21190           
=======================================
+ Hits        14456    14458    +2     
+ Misses       5868     5862    -6     
- Partials      866      870    +4     

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

- **URL**: Link to detailed guidance
- **Metadata**: Restart requirements, dates, entitlements

Critically, remediation `product_ids` often overlap with `product_status` product_ids (e.g., vendor_fix applies to the same products marked as "fixed").
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is a RH issue. And not a common practice. I might be wrong, but to my understanding this isn't allowed right now (in the spec) and will be specifically forbidden in the upcoming 2.1 spec. So I think we should not design for this.

#[derive(Serialize, Deserialize, Debug, Clone, ToSchema)]
pub struct RemediationSummary {
pub id: Uuid,
pub category: String, // vendor_fix, workaround, mitigation, etc.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd love to see this as a enum. Even in the database.

pub category: String, // vendor_fix, workaround, mitigation, etc.
pub details: Option<String>,
pub url: Option<String>,
pub data: Option<serde_json::Value>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe have this as Value only. As it already supports Value::Null.


**Modified Response Structures:**

Add `remediations: Vec<RemediationSummary>` to:
Copy link
Contributor

Choose a reason for hiding this comment

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

I know we did simply add new information to all existing fields in the past. But is that the right idea? Why not start by adding it to the endpoints that require it today.

"status": "affected",
"remediations": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like an internal ID, does it make sense for the user to have it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants