Context
Follow-up split out of #1328. That PR bumped Provenant's CycloneDX output to 1.7 and landed the primary license-expressiveness win — licenses[].acknowledgement (declared vs concluded). The second feature scoped in #1328, component-level license evidence, was explicitly allowed to be deferred if a clean file-to-component mapping turned out to be more than a moderate change. It did, so it is tracked here.
Target
Populate CycloneDX 1.7 component.evidence.licenses (and/or evidence.occurrences with file + line) for each component, using the file-to-component ownership Provenant already has.
Provenant knows the file and line where each license was detected (file.license_detections[].matches[] carry from_file, start_line, end_line). The SPDX renderer already maps files to their owning package via file.for_packages in src/output/spdx_plan.rs (plan_spdx_packages). The CycloneDX renderer (src/output/cyclonedx.rs) currently does not consume output.files at all, so this needs:
- Threading file ownership into the CycloneDX renderer (reuse or generalize the
spdx_plan ownership mapping so both formats agree).
- Emitting
evidence.licenses (observed licenses, acknowledgement omitted or set appropriately) and/or evidence.occurrences (file + line) on the owning component; promoted resolved-dependency components own no scanned files and get no evidence.
- Golden coverage (JSON + XML), and the official 1.7 schema/XSD validator must stay green (
scripts/validate_output_format_fixtures.py).
- Confirm the XML
evidence element ordering against the 1.7 XSD.
Out of scope
References
Context
Follow-up split out of #1328. That PR bumped Provenant's CycloneDX output to 1.7 and landed the primary license-expressiveness win —
licenses[].acknowledgement(declaredvsconcluded). The second feature scoped in #1328, component-level license evidence, was explicitly allowed to be deferred if a clean file-to-component mapping turned out to be more than a moderate change. It did, so it is tracked here.Target
Populate CycloneDX 1.7
component.evidence.licenses(and/orevidence.occurrenceswith file + line) for each component, using the file-to-component ownership Provenant already has.Provenant knows the file and line where each license was detected (
file.license_detections[].matches[]carryfrom_file,start_line,end_line). The SPDX renderer already maps files to their owning package viafile.for_packagesinsrc/output/spdx_plan.rs(plan_spdx_packages). The CycloneDX renderer (src/output/cyclonedx.rs) currently does not consumeoutput.filesat all, so this needs:spdx_planownership mapping so both formats agree).evidence.licenses(observed licenses,acknowledgementomitted or set appropriately) and/orevidence.occurrences(file + line) on the owning component; promoted resolved-dependency components own no scanned files and get no evidence.scripts/validate_output_format_fixtures.py).evidenceelement ordering against the 1.7 XSD.Out of scope
$schema/namespace,acknowledgement).References
src/output/cyclonedx.rs,src/output/spdx_plan.rs,src/output/sbom.rs