From c15246aca64b48da3bc82d2e6eb08022724afaee Mon Sep 17 00:00:00 2001 From: Ander Ruiz Ayesta Date: Wed, 13 May 2026 15:18:29 +0200 Subject: [PATCH 1/2] test(lockfile): add invariant test for LocationRole when BlockLocation is set Any extractor that populates a valid BlockLocation must also set LocationRole. Without it, the reporter emits a blank role field in the SBOM output even though the location is meaningful. The test walks pkg/lockfile/fixtures/, runs the registered extractor for each fixture file, and fails if any PackageDetails has a valid BlockLocation (file + line/column all non-zero) but an empty LocationRole. It is a no-op for files without a registered extractor and silently skips fixtures that intentionally fail to parse. Co-Authored-By: Claude Sonnet 4.6 --- pkg/lockfile/location_role_invariant_test.go | 67 ++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 pkg/lockfile/location_role_invariant_test.go diff --git a/pkg/lockfile/location_role_invariant_test.go b/pkg/lockfile/location_role_invariant_test.go new file mode 100644 index 00000000..4a76a4f0 --- /dev/null +++ b/pkg/lockfile/location_role_invariant_test.go @@ -0,0 +1,67 @@ +package lockfile_test + +import ( + "os" + "path/filepath" + "testing" + + "github.com/DataDog/datadog-sbom-generator/internal/utility/fileposition" + "github.com/DataDog/datadog-sbom-generator/pkg/lockfile" + "github.com/DataDog/datadog-sbom-generator/pkg/lockfile/internal/testutil" + _ "github.com/DataDog/datadog-sbom-generator/pkg/lockfile/parsers" // Register all extractors +) + +// TestLocationRoleSetWhenBlockLocationIsValid verifies that every extractor sets +// LocationRole whenever it also sets a valid BlockLocation. +// +// This is an invariant that the reporter relies on: vulnerability_result.go uses +// LocationRole to populate the "role" field in the emitted PackageLocation. If an +// extractor populates BlockLocation but leaves LocationRole empty, the role will be +// blank in the SBOM output even though the location is meaningful. +// +// The test walks pkg/lockfile/fixtures/, runs the registered extractor for each +// fixture file, and fails if any returned PackageDetails has a valid BlockLocation +// but an empty LocationRole. +func TestLocationRoleSetWhenBlockLocationIsValid(t *testing.T) { + t.Parallel() + + fixturesRoot := "fixtures" + context := testutil.GetTestContext() + + err := filepath.WalkDir(fixturesRoot, func(path string, d os.DirEntry, err error) error { + if err != nil || d.IsDir() { + return err + } + + extractor, _ := lockfile.FindExtractor(path, map[string]bool{}) + if extractor == nil { + return nil + } + + f, err := lockfile.OpenLocalDepFile(path) + if err != nil { + return nil // skip unreadable files + } + defer f.Close() + + packages, err := extractor.Extract(f, context) + if err != nil { + return nil // skip files that fail to parse (invalid fixtures are intentional) + } + + for _, pkg := range packages { + if fileposition.IsFilePositionExtractedSuccessfully(pkg.BlockLocation) && pkg.LocationRole == "" { + t.Errorf( + "extractor for %q returned package %s@%s with a valid BlockLocation but empty LocationRole", + path, pkg.Name, pkg.Version, + ) + } + } + + return nil + }) + + if err != nil { + t.Fatalf("error walking fixtures: %v", err) + } +} From 4be1fa3a630ea7d0dd2130488a577c8dc6beb0e9 Mon Sep 17 00:00:00 2001 From: Ander Ruiz Ayesta Date: Wed, 13 May 2026 15:32:41 +0200 Subject: [PATCH 2/2] fix(test): enable all parsers in location role invariant test Pass allParsers populated from ListSupportedExtractors() to FindExtractor instead of an empty map. An empty map causes FindExtractor to return nil for every fixture, making the test pass vacuously without exercising any extractor. Co-Authored-By: Claude Sonnet 4.6 --- pkg/lockfile/location_role_invariant_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/lockfile/location_role_invariant_test.go b/pkg/lockfile/location_role_invariant_test.go index 4a76a4f0..c27e115f 100644 --- a/pkg/lockfile/location_role_invariant_test.go +++ b/pkg/lockfile/location_role_invariant_test.go @@ -28,12 +28,19 @@ func TestLocationRoleSetWhenBlockLocationIsValid(t *testing.T) { fixturesRoot := "fixtures" context := testutil.GetTestContext() + // Enable all registered parsers so FindExtractor can match fixture files. + // An empty map disables every parser (FindExtractor checks enabledParsers[name] == true). + allParsers := make(map[string]bool) + for name := range lockfile.ListSupportedExtractors() { + allParsers[name] = true + } + err := filepath.WalkDir(fixturesRoot, func(path string, d os.DirEntry, err error) error { if err != nil || d.IsDir() { return err } - extractor, _ := lockfile.FindExtractor(path, map[string]bool{}) + extractor, _ := lockfile.FindExtractor(path, allParsers) if extractor == nil { return nil }