Skip to content

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

Open
fahedouch wants to merge 2 commits intoDependencyTrack:mainfrom
fahedouch:feature/rating-source-tracking
Open

Add rating source tracking for context-aware OWASP scores#1928
fahedouch wants to merge 2 commits intoDependencyTrack:mainfrom
fahedouch:feature/rating-source-tracking

Conversation

@fahedouch
Copy link
Copy Markdown

@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 (fixes #5796).

What changed

I added a precedence system to track where OWASP ratings come 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.

I applied Considerations about when to provide severity, vector and/or score fields which are recently proposed in openvex rating field integration qui me semble pertinente :

  • At least severity or vector must be provided
  • If vector is provided, score must accompany it

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

Additional Details

Checklist

  • I have read and understand the contributing guidelines
  • This PR fixes a defect, and I have provided tests to verify that the fix is effective
  • 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.
@fahedouch
Copy link
Copy Markdown
Author

Frontend PR

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

Signed-off-by: Fahed Dorgaa <fahed.dorgaa@gmail.com>
@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch 2 times, most recently from e5b23d3 to e791dc0 Compare April 8, 2026 15:11
Signed-off-by: Fahed Dorgaa <fahed.dorgaa@gmail.com>
@fahedouch fahedouch force-pushed the feature/rating-source-tracking branch from e791dc0 to ad2c4a5 Compare April 8, 2026 15:12
@codacy-production
Copy link
Copy Markdown

codacy-production bot commented Apr 8, 2026

Not up to standards ⛔

🟢 Issues 10 minor

Results:
10 new issues

Category Results
CodeStyle 10 minor

View in Codacy

🟢 Metrics 38 complexity

Metric Results
Complexity 38

View in Codacy

🔴 Coverage 57.26% diff coverage · -0.26% coverage variation

Metric Results
Coverage variation -0.26% coverage variation (-1.00%)
Diff coverage 57.26% diff coverage (70.00%)

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (7b650af) 26069 22357 85.76%
Head commit (ad2c4a5) 27649 (+1580) 23640 (+1283) 85.50% (-0.26%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#1928) 124 71 57.26%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

TIP This summary will be updated as you push new changes. Give us feedback

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?

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.

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

3 participants