fix: keep archive CONTAINS package edges in SPDX

the SPDX writer only kept relationships whose `From` is a package, so the `file CONTAINS package` edges the archive task records were dropped. For anything that isn't java (npm in a tgz, python in a zip) that edge is the only thing saying which archive a package came out of.

SPDX now also writes `CONTAINS` from a file to a package. The file end is always in the document, since `toFiles` covers every coordinate a relationship names. Other file-side relationships (e.g. binary's file `DEPENDENCY_OF` package) are still dropped as before.

CycloneDX is unchanged: it has no file components to hang the edge on, and war-to-jar structure reaches it through the java `DEPENDENCY_OF` parity fix.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman
2026-09-24 13:41:39 -04:00
parent b735b615f0
commit 9dbef8e831
2 changed files with 29 additions and 3 deletions
@@ -644,8 +644,11 @@ func toRelationships(relationships []artifact.Relationship) (result []*spdx.Rela
continue
}
// FIXME: we are only currently including Package -> * relationships
if _, ok := r.From.(pkg.Package); !ok {
// FIXME: we are only currently including Package -> * relationships, plus an archive containing a
// package found inside it, which is the only structure nested archive cataloging records for
// non-java packages. Every file-side From is in the document: toFiles covers every coordinate a
// relationship names.
if _, ok := r.From.(pkg.Package); !ok && !isFileContainsPackage(r) {
log.Debugf("skipping non-package relationship: %+v", r)
continue
}
@@ -664,6 +667,12 @@ func toRelationships(relationships []artifact.Relationship) (result []*spdx.Rela
return result
}
func isFileContainsPackage(r artifact.Relationship) bool {
_, fromFile := r.From.(file.Coordinates)
_, toPkg := r.To.(pkg.Package)
return fromFile && toPkg && r.Type == artifact.ContainsRelationship
}
func lookupRelationship(ty artifact.RelationshipType) (bool, helpers.RelationshipType, string) {
switch ty {
case artifact.ContainsRelationship:
@@ -810,7 +810,7 @@ func Test_fileIDsForPackage(t *testing.T) {
expected: nil,
},
{
name: "ignore file-to-package",
name: "include an archive file containing a package",
relationships: []artifact.Relationship{
{
From: c,
@@ -818,6 +818,23 @@ func Test_fileIDsForPackage(t *testing.T) {
Type: artifact.ContainsRelationship,
},
},
expected: []*spdx.Relationship{
{
Relationship: "CONTAINS",
RefA: docElementId(c),
RefB: docElementId(p),
},
},
},
{
name: "ignore other file-to-package",
relationships: []artifact.Relationship{
{
From: c,
To: p,
Type: artifact.DependencyOfRelationship,
},
},
expected: nil,
},
{