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 <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman
2026-09-24 11:20:04 -04:00
parent 3f0a599d31
commit ccc4832ff6
5 changed files with 26 additions and 4 deletions
+14
View File
@@ -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
+1
View File
@@ -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"`
+2 -1
View File
@@ -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,
+5 -1
View File
@@ -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,
+4 -2
View File
@@ -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) {