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 continue
} }
// FIXME: we are only currently including Package -> * relationships // FIXME: we are only currently including Package -> * relationships, plus an archive containing a
if _, ok := r.From.(pkg.Package); !ok { // 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) log.Debugf("skipping non-package relationship: %+v", r)
continue continue
} }
@@ -664,6 +667,12 @@ func toRelationships(relationships []artifact.Relationship) (result []*spdx.Rela
return result 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) { func lookupRelationship(ty artifact.RelationshipType) (bool, helpers.RelationshipType, string) {
switch ty { switch ty {
case artifact.ContainsRelationship: case artifact.ContainsRelationship:
@@ -810,7 +810,7 @@ func Test_fileIDsForPackage(t *testing.T) {
expected: nil, expected: nil,
}, },
{ {
name: "ignore file-to-package", name: "include an archive file containing a package",
relationships: []artifact.Relationship{ relationships: []artifact.Relationship{
{ {
From: c, From: c,
@@ -818,6 +818,23 @@ func Test_fileIDsForPackage(t *testing.T) {
Type: artifact.ContainsRelationship, 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, expected: nil,
}, },
{ {