From ccc4832ff671f531021ca5e952a4deb54cb3bde6 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 24 Sep 2026 11:20:04 -0400 Subject: [PATCH] fix: record archive search in the SBOM descriptor nothing in the output said nested archive cataloging ran, or how deep it went: `Archive` wasn't in the configuration audit trail, and `archive-cataloger` never showed up in `catalogers.used`. - the audit trail gains an `archive` section with the top-level archive config - `catalogers.used` includes `archive-cataloger` when the task is scheduled - the `packages` section now reports java's config after the archive search booleans are overlaid, i.e. what java actually used `descriptor.configuration` is untyped in the schema, so no schema change. Signed-off-by: Alex Goodman --- syft/archive_cataloger_test.go | 14 ++++++++++++++ syft/configuration_audit_trail.go | 1 + syft/create_sbom.go | 3 ++- syft/create_sbom_config.go | 6 +++++- syft/create_sbom_config_test.go | 6 ++++-- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/syft/archive_cataloger_test.go b/syft/archive_cataloger_test.go index 59f746453..efb222d27 100644 --- a/syft/archive_cataloger_test.go +++ b/syft/archive_cataloger_test.go @@ -19,6 +19,7 @@ import ( "github.com/wagoodman/go-progress" "github.com/anchore/syft/internal/bus" + "github.com/anchore/syft/internal/task" "github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/cataloging" "github.com/anchore/syft/syft/cataloging/filecataloging" @@ -329,6 +330,19 @@ func TestArchiveCataloger_featureOff(t *testing.T) { }) } +func TestArchiveCataloger_descriptorRecordsArchiveConfig(t *testing.T) { + // a consumer must be able to tell from the SBOM alone how deep archive contents were searched + cfg := DefaultCreateSBOMConfig(). + WithCatalogerSelection(cataloging.NewSelectionRequest().WithDefaults("java")). + WithArchiveConfig(cataloging.DefaultArchiveSearchConfig().WithMaxDepth(3)) + s := scanDirWithExclusions(t, t.TempDir(), cfg) + + trail, ok := s.Descriptor.Configuration.(configurationAuditTrail) + require.True(t, ok) + assert.Equal(t, 3, trail.Archive.MaxDepth) + assert.Contains(t, trail.Catalogers.Used, task.ArchiveCatalogerTaskName) +} + func TestArchiveCataloger_javaArchiveDepthIsAConfigError(t *testing.T) { // depth and limits are not java settings; setting them on java's deprecated copy must fail fast // rather than be silently ignored diff --git a/syft/configuration_audit_trail.go b/syft/configuration_audit_trail.go index aa7a51f4d..f5f456689 100644 --- a/syft/configuration_audit_trail.go +++ b/syft/configuration_audit_trail.go @@ -16,6 +16,7 @@ type configurationAuditTrail struct { DataGeneration cataloging.DataGenerationConfig `json:"data-generation" yaml:"data-generation" mapstructure:"data-generation"` Packages pkgcataloging.Config `json:"packages" yaml:"packages" mapstructure:"packages"` Files filecataloging.Config `json:"files" yaml:"files" mapstructure:"files"` + Archive cataloging.ArchiveSearchConfig `json:"archive" yaml:"archive" mapstructure:"archive"` Licenses cataloging.LicenseConfig `json:"licenses" yaml:"licenses" mapstructure:"licenses"` Catalogers catalogerManifest `json:"catalogers" yaml:"catalogers" mapstructure:"catalogers"` ExtraConfigs any `json:"extra,omitempty" yaml:"extra" mapstructure:"extra"` diff --git a/syft/create_sbom.go b/syft/create_sbom.go index 89755c86a..22c35e26f 100644 --- a/syft/create_sbom.go +++ b/syft/create_sbom.go @@ -58,8 +58,9 @@ func CreateSBOM(ctx context.Context, src source.Source, cfg *CreateSBOMConfig) ( Search: cfg.Search, Relationships: cfg.Relationships, DataGeneration: cfg.DataGeneration, - Packages: cfg.Packages, + Packages: cfg.packagesWithArchiveSearch(), Files: cfg.Files, + Archive: cfg.Archive, Licenses: cfg.Licenses, Catalogers: *audit, ExtraConfigs: cfg.ToolConfiguration, diff --git a/syft/create_sbom_config.go b/syft/create_sbom_config.go index bb64e438d..423a5973e 100644 --- a/syft/create_sbom_config.go +++ b/syft/create_sbom_config.go @@ -221,7 +221,8 @@ func (c *CreateSBOMConfig) makeTaskGroups(src source.Description, exclusions []s // the same package and file catalogers run against the contents of every archive, after the scan // root and before relationship and unknowns post-processing - if archiveTask := task.NewArchiveCatalogerTask(c.Archive, append(slices.Clone(pkgTasks), fileTasks...), exclusions); archiveTask != nil { + archiveTask := task.NewArchiveCatalogerTask(c.Archive, append(slices.Clone(pkgTasks), fileTasks...), exclusions) + if archiveTask != nil { taskGroups = append(taskGroups, []task.Task{archiveTask}) } @@ -256,6 +257,9 @@ func (c *CreateSBOMConfig) makeTaskGroups(src source.Description, exclusions []s var allTasks []task.Task allTasks = append(allTasks, pkgTasks...) allTasks = append(allTasks, fileTasks...) + if archiveTask != nil { + allTasks = append(allTasks, archiveTask) + } return taskGroups, &catalogerManifest{ Requested: selectionEvidence.Request, diff --git a/syft/create_sbom_config_test.go b/syft/create_sbom_config_test.go index 08290d1fe..12dc46bd3 100644 --- a/syft/create_sbom_config_test.go +++ b/syft/create_sbom_config_test.go @@ -583,9 +583,10 @@ func TestCreateSBOMConfig_archiveTaskGroup(t *testing.T) { t.Run("no archive task by default", func(t *testing.T) { // the feature is off by default, and off must mean no task at all rather than a registered // task that does nothing: a registered task is reported as a selected cataloger - groups, _, err := DefaultCreateSBOMConfig().makeTaskGroups(src, nil) + groups, manifest, err := DefaultCreateSBOMConfig().makeTaskGroups(src, nil) require.NoError(t, err) assert.False(t, archiveTaskIn(groups)) + assert.NotContains(t, manifest.Used, task.ArchiveCatalogerTaskName) }) t.Run("archive task is present at negative depth", func(t *testing.T) { @@ -599,9 +600,10 @@ func TestCreateSBOMConfig_archiveTaskGroup(t *testing.T) { t.Run("archive task is present when enabled", func(t *testing.T) { cfg := DefaultCreateSBOMConfig(). WithArchiveConfig(cataloging.DefaultArchiveSearchConfig().WithMaxDepth(2)) - groups, _, err := cfg.makeTaskGroups(src, nil) + groups, manifest, err := cfg.makeTaskGroups(src, nil) require.NoError(t, err) assert.True(t, archiveTaskIn(groups)) + assert.Contains(t, manifest.Used, task.ArchiveCatalogerTaskName, "the manifest must say archive contents were searched") }) t.Run("enabling the feature does not mutate the caller's package config", func(t *testing.T) {