Merge PR #4044: recursive nested-archive scanning at the resolver layer

Adds recursive archive indexing/traversal in the fileresolver and source
provider layers.

Original work by @Rupikz in anchore/syft#4044.

# Conflicts:
#	cmd/syft/internal/options/source.go
#	syft/internal/fileresolver/directory.go
#	syft/internal/fileresolver/filetree_resolver.go
#	syft/internal/fileresolver/filetree_resolver_test.go
#	syft/pkg/cataloger/java/internal/maven/resolver_test.go
#	syft/source/directorysource/directory_source.go
#	test/cli/archive_test.go
This commit is contained in:
Keith Zantow
2026-06-30 16:50:23 +00:00
18 changed files with 541 additions and 133 deletions
+1
View File
@@ -227,6 +227,7 @@ func getSource(ctx context.Context, opts *options.Catalog, userInput string, sou
Paths: opts.Exclusions,
}).
WithBasePath(opts.Source.BasePath).
WithMaxArchiveRecursiveIndexDepth(opts.Source.Directory.MaxArchiveRecursiveIndexDepth).
WithSources(sources...).
WithDefaultImagePullSource(opts.Source.Image.DefaultPullSource)
+33 -21
View File
@@ -14,36 +14,25 @@ import (
)
type sourceConfig struct {
Name string `json:"name" yaml:"name" mapstructure:"name"`
Version string `json:"version" yaml:"version" mapstructure:"version"`
Supplier string `json:"supplier" yaml:"supplier" mapstructure:"supplier"`
Source string `json:"source" yaml:"source" mapstructure:"source"`
BasePath string `yaml:"base-path" json:"base-path" mapstructure:"base-path"` // specify base path for all file paths
File fileSource `json:"file" yaml:"file" mapstructure:"file"`
Image imageSource `json:"image" yaml:"image" mapstructure:"image"`
Name string `json:"name" yaml:"name" mapstructure:"name"`
Version string `json:"version" yaml:"version" mapstructure:"version"`
Supplier string `json:"supplier" yaml:"supplier" mapstructure:"supplier"`
Source string `json:"source" yaml:"source" mapstructure:"source"`
BasePath string `yaml:"base-path" json:"base-path" mapstructure:"base-path"` // specify base path for all file paths
File fileSource `json:"file" yaml:"file" mapstructure:"file"`
Directory directorySource `json:"directory" yaml:"directory" mapstructure:"directory"`
Image imageSource `json:"image" yaml:"image" mapstructure:"image"`
}
type fileSource struct {
Digests []string `json:"digests" yaml:"digests" mapstructure:"digests"`
}
var _ interface {
clio.FieldDescriber
} = (*sourceConfig)(nil)
var _ clio.PostLoader = (*imageSource)(nil)
var _ clio.FieldDescriber = (*sourceConfig)(nil)
func (o *sourceConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
descriptions.Add(&o.File.Digests, `the file digest algorithms to use on the scanned file (options: "md5", "sha1", "sha224", "sha256", "sha384", "sha512")`)
descriptions.Add(&o.Directory.MaxArchiveRecursiveIndexDepth, `depth to recursively resolve archive parents, no limit if == -1`)
descriptions.Add(&o.Image.DefaultPullSource, `allows users to specify which image source should be used to generate the sbom
valid values are: registry, docker, podman`)
}
type imageSource struct {
DefaultPullSource string `json:"default-pull-source" yaml:"default-pull-source" mapstructure:"default-pull-source"`
MaxLayerSize string `json:"max-layer-size" yaml:"max-layer-size" mapstructure:"max-layer-size"`
}
func defaultSourceConfig() sourceConfig {
var digests []string
for _, alg := range sourceproviders.DefaultConfig().DigestAlgorithms {
@@ -56,6 +45,12 @@ func defaultSourceConfig() sourceConfig {
}
}
var _ clio.PostLoader = (*fileSource)(nil)
type fileSource struct {
Digests []string `json:"digests" yaml:"digests" mapstructure:"digests"`
}
func (c *fileSource) PostLoad() error {
digests := strset.New(c.Digests...).List()
sort.Strings(digests)
@@ -63,6 +58,23 @@ func (c *fileSource) PostLoad() error {
return nil
}
var _ clio.PostLoader = (*directorySource)(nil)
type directorySource struct {
MaxArchiveRecursiveIndexDepth int `json:"max-archive-recursive-index-depth" yaml:"max-archive-recursive-index-depth" mapstructure:"max-archive-recursive-index-depth"`
}
func (c *directorySource) PostLoad() error {
return nil
}
var _ clio.PostLoader = (*imageSource)(nil)
type imageSource struct {
DefaultPullSource string `json:"default-pull-source" yaml:"default-pull-source" mapstructure:"default-pull-source"`
MaxLayerSize string `json:"max-layer-size" yaml:"max-layer-size" mapstructure:"max-layer-size"`
}
func (c *imageSource) PostLoad() error {
if c.MaxLayerSize != "" {
perFileReadLimit, err := humanize.ParseBytes(c.MaxLayerSize)