Skip to content
This repository was archived by the owner on May 30, 2026. It is now read-only.

Add rating source tracking for context-aware OWASP scores#1928

Open
fahedouch wants to merge 1 commit into
DependencyTrack:mainfrom
fahedouch:feature/rating-source-tracking
Open

Add rating source tracking for context-aware OWASP scores#1928
fahedouch wants to merge 1 commit into
DependencyTrack:mainfrom
fahedouch:feature/rating-source-tracking

Conversation

@fahedouch
Copy link
Copy Markdown
Contributor

@fahedouch fahedouch commented Mar 24, 2026

Description

fix DependencyTrack/dependency-track#5796

This PR enables context-aware OWASP Risk Rating scores at the component level, so the same CVE can have different scores depending on the deployment context.

What changed

Added a precedence system to track where analysis ownership comes from:

  • POLICY (highest) - organizational standards
  • VEX - authoritative context-aware assessments
  • MANUAL - analyst notes
  • NVD (lowest) - default database scores

Higher precedence sources can overwrite lower ones, but not vice versa. This prevents VEX imports from accidentally overwriting your policy ratings or analyst assessments.

OWASP ratings store vector + score, no separate severity column — consistent with how CVSS is handled on Analysis.

Use case

Import contextual OWASP scores from VEX documents (e.g., generated by VENS) that reflect your actual deployment - internet-facing vs internal, production vs dev, sensitive data handling, etc.

Addressed Issue

fixes DependencyTrack/dependency-track#5796

Checklist

  • I have read and understand the contributing guidelines
  • This PR implements an enhancement, and I have provided tests to verify that it works as intended
  • This PR introduces changes to the database model, and I have updated the migration changelog accordingly
  • This PR introduces new or alters existing behavior, and I have updated the documentation accordingly

Copilot AI review requested due to automatic review settings March 24, 2026 17:34
@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch from faf1f2a to 1b90695 Compare March 24, 2026 17:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces tracking of the source of component-level OWASP Risk Rating overrides so that context-aware scores (e.g., from VEX) can be applied with a defined precedence model, aiming to prevent lower-precedence sources from overwriting higher-precedence ratings.

Changes:

  • Adds a new OWASPSOURCE column to ANALYSIS plus an index, and wires it into the Analysis model.
  • Introduces a RatingSource enum with precedence + overwrite logic, and adds unit tests for it.
  • Extends analysis update flows to carry OWASP vector/score/source via MakeAnalysisCommand, and imports OWASP ratings from CycloneDX VEX as RatingSource.VEX.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
migration/src/main/resources/migration/changelog-v5.8.0.xml Adds OWASPSOURCE column and index in Liquibase.
migration/src/main/resources/migration/changelog-main.xml Includes the v5.8.0 changelog in the master migration chain.
apiserver/src/test/java/org/dependencytrack/model/RatingSourceTest.java Adds tests validating precedence and overwrite behavior.
apiserver/src/main/java/org/dependencytrack/persistence/command/MakeAnalysisCommand.java Adds OWASP vector/score/source fields and a convenience withOwasp(...) method.
apiserver/src/main/java/org/dependencytrack/persistence/AnalysisQueryManager.java Applies precedence when updating OWASP vector/score and persists owaspSource.
apiserver/src/main/java/org/dependencytrack/parser/cyclonedx/CycloneDXVexImporter.java Imports OWASP ratings from CycloneDX VEX and sets source to VEX, with basic validation.
apiserver/src/main/java/org/dependencytrack/model/RatingSource.java Defines precedence order and overwrite logic.
apiserver/src/main/java/org/dependencytrack/model/Analysis.java Adds the persisted owaspSource field mapped to OWASPSOURCE.
RATING_SOURCE_TRACKING.md Documents the precedence model and examples.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import java.math.BigDecimal;
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

java.math.BigDecimal is imported but never used in this class. This will fail compilation due to an unused import; please remove it (or use it if intended).

Suggested change
import java.math.BigDecimal;

Copilot uses AI. Check for mistakes.
Comment on lines +238 to +240
* <li>MANUAL - User-provided ratings</li>
* <li>VEX - Ratings from VEX documents</li>
* <li>POLICY - Ratings from organizational policies</li>
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

The precedence order documented here (MANUAL > VEX > POLICY > NVD) contradicts the precedence defined in RatingSource (POLICY > VEX > MANUAL > NVD) and the PR description. Please correct the Javadoc to reflect the actual precedence to avoid future logic being implemented based on the wrong ordering.

Suggested change
* <li>MANUAL - User-provided ratings</li>
* <li>VEX - Ratings from VEX documents</li>
* <li>POLICY - Ratings from organizational policies</li>
* <li>POLICY - Ratings from organizational policies</li>
* <li>VEX - Ratings from VEX documents</li>
* <li>MANUAL - User-provided ratings</li>

Copilot uses AI. Check for mistakes.
Comment on lines +201 to +205
command = command.withOwasp(
rating.getVector(),
rating.getScore(),
RatingSource.VEX);
break; // Only use the first OWASP rating
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

For OWASP ratings, this logic allows a rating with severity != null but vector == null (and potentially score == null) to be treated as valid, then it calls withOwasp(null, null, VEX) and immediately breaks. That means a later OWASP rating with a usable vector+score in the same VEX document would be ignored, and no OWASP data will be applied. Consider requiring vector+score for OWASP imports (since those are the only fields persisted), or only break once at least one of vector/score is actually applied.

Suggested change
command = command.withOwasp(
rating.getVector(),
rating.getScore(),
RatingSource.VEX);
break; // Only use the first OWASP rating
if (rating.getVector() == null || rating.getScore() == null) {
LOGGER.warn("VEX OWASP rating is missing vector and/or score - skipping");
continue;
}
command = command.withOwasp(
rating.getVector(),
rating.getScore(),
RatingSource.VEX);
break; // Only use the first OWASP rating with usable vector and score

Copilot uses AI. Check for mistakes.
Comment on lines +155 to +158
@Persistent(defaultFetchGroup = "true")
@Column(name = "OWASPSOURCE", jdbcType = "VARCHAR")
@JsonProperty(value = "owaspSource")
private RatingSource owaspSource;
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Adding owaspSource to the JDO model is not sufficient to enforce precedence if OWASP scores/vectors are also written via the JDBI-based policy/analysis upserts: those SQL paths currently don't read/write OWASPSOURCE, so the column will remain NULL or stale while OWASPVECTOR/OWASPSCORE change. This breaks the intended precedence rules (e.g., policy updates won't mark the source as POLICY, and VEX may overwrite rows with NULL source). Please update the relevant JDBI mappers/queries/upserts to include OWASPSOURCE wherever OWASP ratings are set.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +17
<addColumn tableName="ANALYSIS">
<column name="OWASPSOURCE" type="VARCHAR(50)">
<constraints nullable="true"/>
</column>
</addColumn>
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

The new OWASPSOURCE column is nullable and there's no data migration/backfill. As a result, any existing analyses that already have OWASPVECTOR/OWASPSCORE populated will have a NULL source and will be treated as overwritable by any new source (since canOverwrite(null) returns true). If the goal is to prevent VEX imports from overwriting existing policy/manual ratings, consider backfilling OWASPSOURCE for existing rows (or introducing an explicit default/UNKNOWN source with appropriate precedence).

Copilot uses AI. Check for mistakes.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Static wildcard import is disallowed by this repo's Checkstyle rules (AvoidStarImport in support/checkstyle/config.xml). Please replace import static org.junit.jupiter.api.Assertions.*; with explicit static imports for the assertions used in this test.

Suggested change
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

Copilot uses AI. Check for mistakes.
Comment thread apiserver/src/main/java/org/dependencytrack/model/Analysis.java Outdated
@fahedouch
Copy link
Copy Markdown
Contributor Author

Frontend PR

Capture d’écran 2026-03-30 à 23 57 09

@fahedouch fahedouch requested a review from nscuro March 31, 2026 09:24
@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch 3 times, most recently from e791dc0 to ad2c4a5 Compare April 8, 2026 15:12
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Apr 8, 2026

Up to standards ✅

🟢 Issues 10 minor

Results:
10 new issues

Category Results
CodeStyle 10 minor

View in Codacy

🟢 Metrics 35 complexity

Metric Results
Complexity 35

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Comment on lines +155 to +162
@Persistent(defaultFetchGroup = "true")
@Column(name = "OWASPSEVERITY")
@Extensions(value = {
@Extension(vendorName = "datanucleus", key = "insert-function", value = "CAST(? AS severity)"),
@Extension(vendorName = "datanucleus", key = "update-function", value = "CAST(? AS severity)")
})
@JsonProperty(value = "owaspSeverity")
private Severity owaspSeverity;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is the use case for tracking the severity for OWASP ratings separately? Adding more severity fields adds complexity to all queries that operate on severities, including metrics calculation.

Analogue to a previous comment, if we do this for OWASP ratings, why not also for CVSS?

Copy link
Copy Markdown
Contributor Author

@fahedouch fahedouch Apr 17, 2026

Choose a reason for hiding this comment

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

Makes sense, dropped owaspSeverity — no separate severity column for CVSS either, no reason to add one for OWASP.

@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch 6 times, most recently from 425ff0a to 964150c Compare April 17, 2026 13:44
@fahedouch fahedouch requested a review from nscuro April 17, 2026 14:22
@fahedouch
Copy link
Copy Markdown
Contributor Author

fahedouch commented Apr 17, 2026

@nscuro thank you for the review. I’ve addressed your latest comments.

Two questions before I go further:

1. OWASP rating validation in VEX imports
Right now the importer skips OWASP ratings if vector or score is missing. CVSS fields elsewhere in the codebase are independent though (you can have a score without a vector, or vice versa). Should I relax this to match, or keep both required for OWASP?

2. Scope of the precedence guard
The source-based precedence currently only protects OWASP vector/score — state, justification, response, suppression are still updatable regardless of source. I kept it scoped to ratings intentionally. Worth extending to the full analysis, or fine as-is for now?

@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch from ae67a02 to abb31ba Compare April 17, 2026 16:49
@nscuro
Copy link
Copy Markdown
Member

nscuro commented Apr 23, 2026

@fahedouch

  1. OWASP rating validation in VEX imports
    Right now the importer skips OWASP ratings if vector or score is missing. CVSS fields elsewhere in the codebase are independent though (you can have a score without a vector, or vice versa). Should I relax this to match, or keep both required for OWASP?

I'd say relax it. If we enforce invariants it should be consistent.

  1. Scope of the precedence guard
    The source-based precedence currently only protects OWASP vector/score — state, justification, response, suppression are still updatable regardless of source. I kept it scoped to ratings intentionally. Worth extending to the full analysis, or fine as-is for now?

It should be scoped to the entire analysis, otherwise ownership becomes messy or even impossible to track.

@fahedouch
Copy link
Copy Markdown
Contributor Author

Thanks @nscuro, both addressed:

  1. Relaxed VEX OWASP validation — vector or score alone is now accepted, consistent with CVSS handling.
  2. Extended precedence guard to the full analysis (state, justification, response, details, suppression) — not just OWASP fields anymore.

@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch from f1a9da8 to 15bcba3 Compare April 24, 2026 14:04
@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch from 15bcba3 to 1eb3c24 Compare May 12, 2026 10:29
@fahedouch
Copy link
Copy Markdown
Contributor Author

fahedouch commented May 20, 2026

@nscuro squashed into one commit, should be easier to review now.

Quick reading order if you're short on time:

  1. RatingSource.java (46 lines) — the enum with precedence
  2. AnalysisQueryManager — the canUpdate guard, wraps all field updates now
  3. Analysis.java — just a SOURCE column + getter/setter
  4. CycloneDXVexImporter — handles OWASP ratings from VEX, sets source = VEX
  5. AnalysisResource — REST path sets source = MANUAL

JDBI is wired too — AnalysisDao writes SOURCE = POLICY on upsert, VulnerabilityPolicyDao clears it on unassign, AnalysisRowMapper reads it.

Migration is one Flyway file: column + index + backfill.

Your previous feedback is all in — per-analysis ownership, no owaspSeverity, precedence on full analysis, relaxed VEX validation.

@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch from 1eb3c24 to 70e187d Compare May 20, 2026 15:14
Signed-off-by: Fahed Dorgaa <fahed.dorgaa@gmail.com>
@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch from 70e187d to 67db5ce Compare May 20, 2026 15:26
@nscuro
Copy link
Copy Markdown
Member

nscuro commented May 29, 2026

Hi @fahedouch, in preparation of the v5 GA release we have migrated the code to the canonical dependency-track repository. Please kindly re-target your PR as per https://github.com/DependencyTrack/dependency-track/blob/main/V5_MIGRATION.md#contributors-and-pr-authors.

@fahedouch
Copy link
Copy Markdown
Contributor Author

fahedouch commented May 29, 2026

Thanks @nscuro. Re-opened it on dependency-track: DependencyTrack/dependency-track

Just to make sure I understand: hyades-apiserver will be archived and everything v5 lives under dependency-track from now on, so "hyades" as a name is basically going away?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OWASP scores should be per-component, not global, to support contextual VEX ratings

3 participants