Skip to content

Add durable component license curation: component analyses, policies, and read-only imported components - #6961

Open
canikrichard wants to merge 6 commits into
DependencyTrack:mainfrom
brightpick:component-audit-main
Open

canikrichard wants to merge 6 commits into
DependencyTrack:mainfrom
brightpick:component-audit-main

Conversation

@canikrichard

@canikrichard canikrichard commented Aug 12, 2026

Copy link
Copy Markdown

Description

Adds durable, audited license curation for components. When a BOM declares a component's license incorrectly (or omits it), the only options today are suppressing the resulting policy violation — which hides a finding instead of correcting the data — or editing the component via REST, which the next BOM upload silently reverts. This PR makes the license correction a first-class concept that survives re-uploads:

  • Component analyses: a per-component license override with free-text details, keyed by the component's identity (purl, falling back to group/name/version) within a project, so it survives component rows being recreated on every import. Every field change appends an audit comment (old value, new value, author). The BOM-declared license is snapshotted on first override, so clearing the override restores it. Overrides are re-applied at the end of every BOM import — after field synchronization, before policy evaluation — so LICENSE policy violations always evaluate against the curated license.
  • Component policies: CEL conditions over component and project fields that maintain the same analyses automatically on every import, first-match-wins by priority. Manual analyses always win over policy-maintained ones; when a policy stops matching, its analysis is retracted and the imported license applies again. Policy actions write the same audit trail, with the policy as author.
  • Spec-first v2 REST API for both: /component-analyses (+ {id}, {id}/comments) and /component-policies (+ {id}).
  • Imported components become read-only: update, delete, and property mutations respond 405 for BOM-originated components — the BOM stays their single source of truth, and curation happens through analyses and policies. Components created manually via REST carry a MANUALLY_CREATED flag, remain fully editable, and are never deleted by BOM synchronization; if a BOM component later matches a manual component's identity, the BOM takes ownership (the flag clears and the component becomes read-only).

Addressed Issue

Closes #251

Additional Details

  • The design and its trade-offs are recorded in ADR 036, included in this PR.
  • Keying analyses by component identity instead of the component row was the central decision: rows are deleted and recreated as components enter and leave the BOM, so nothing keyed to the row survives an upload. Identity (purl / group+name+version within the project) is the stable handle.
  • ImportBomActivity gains a single hook at the end of component processing — deliberately the only touch point in the ingestion path.
  • The last commit adds a Dao-level test for the vulnerabilities-by-component duplicate-rows bug fixed in bb9d2c9; it additionally pins that a sibling component's suppression neither hides nor leaks into another component's findings.
  • Breaking change to be aware of: API consumers that mutate BOM-imported components will now receive 405 and need to migrate to component analyses. Everything else is additive (new tables COMPONENT_ANALYSIS, COMPONENT_ANALYSIS_COMMENT, COMPONENT_POLICY via migration V202608121000, plus the MANUALLY_CREATED component flag).
  • Verified locally: the 9 touched test classes pass (207 tests, 0 failures), including new suites for both v2 resources and the import re-application logic.

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
  • This PR is a substantial change (per the ADR criteria), and I have added an ADR under docs/adr/

canikrichard and others added 6 commits August 12, 2026 10:59
License corrections must survive BOM re-uploads, carry an audit
trail, and be automatable; ad-hoc component edits provide none of
that. ADR 029 records the design: identity-keyed component analyses,
CEL-driven component policies on top, and read-only imported
components with a manual-component escape hatch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Richard Canik <canik@brightpick.ai>
A component analysis stores a license override and free-text details
per component, keyed by the component's identity (purl, falling back
to group/name/version) within a project. Component rows are deleted
and recreated across BOM uploads, so identity keys are the only way
for a curation to survive; the analysis is re-applied at the end of
every BOM import, after field synchronization and before policy
evaluation, so LICENSE violations always evaluate against the curated
license. The BOM-declared license is snapshotted on first override,
letting a cleared override restore the uploaded value instantly.
Every change appends an audit comment.

The migration ships the complete curation schema, including the
COMPONENT_POLICY table that analyses reference via POLICY_ID; the
policy machinery itself lands in a follow-up commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Richard Canik <canik@brightpick.ai>
Spec-first v2 endpoints for durable license curation: list the
analyses of a project, upsert an analysis by component identity,
delete one, and read or append audit-trail comments. Upserting
resolves the license (SPDX ID or custom license name, rejected with
400 when unknown), records per-field audit comments, and immediately
applies the override to matching components so a correction is
visible without waiting for the next upload.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Richard Canik <canik@brightpick.ai>
A component policy is a CEL condition over component and project
fields plus a license and details to apply on match. Policies are
evaluated at every BOM import in priority order, first match wins,
optionally limited to a validity window. A matching policy maintains
a component analysis carrying its patch and writes the same per-field
audit comments as manual curation, authored as the policy. Manual
analyses always win over policies, and when no policy matches anymore
the policy-maintained analysis is retracted so the imported license
applies again. CRUD lives under /api/v2/component-policies; the CEL
condition is compiled server-side and rejected with 400 when invalid.
Protos for evaluation are built from the in-flight JDO components so
first-upload matching works before the transaction commits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Richard Canik <canik@brightpick.ai>
Components imported from BOM uploads are managed exclusively by the
uploads themselves; ad-hoc REST mutations would be overwritten by the
next upload or bypass the curation audit trail. Component update,
delete, and property mutations therefore respond 405 unless the
component was created manually through the REST API.

Manually created components carry a MANUALLY_CREATED flag, stay fully
editable, and are never deleted by BOM synchronization. When a BOM
component matches a manual component's identity, the BOM takes
ownership: the flag clears and the component becomes read-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Richard Canik <canik@brightpick.ai>
Upstream bb9d2c9 fixed the analysis join fanning out duplicate rows
when a project has more than one analysis for the same vulnerability.
This test pins the Dao behaviour directly, including that a sibling
component's suppression neither hides nor leaks into another
component's findings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Richard Canik <canik@brightpick.ai>
@owasp-dt-bot

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 163 complexity

Metric Results
Complexity 163

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.

@canikrichard canikrichard changed the title wip Add durable component license curation: component analyses, policies, and read-only imported components Aug 12, 2026
@canikrichard
canikrichard marked this pull request as ready for review August 12, 2026 10:08
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.

Scan import overwriting user-specified data (eg licences)

2 participants