mirror of
https://github.com/anchore/syft.git
synced 2026-10-30 14:02:26 +01:00
fix: run root file catalogers after the archive task with owned-by-package selection
with nested cataloging on, java leaves root-level archives to the archive task, so a root `app.jar` package only exists once that task has run. With the default `FilesOwnedByPackageSelection` the root file catalogers ran in an earlier group, never saw the package, and `app.jar` got no file metadata or digests. It did get them with the feature off. - in owned-by-package mode the groups are now packages, then the archive task, then the root file tasks. Other modes are unchanged - the file tasks merge their results into the SBOM instead of replacing the maps, since the archive task has already written nested files into them Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
@@ -48,7 +48,7 @@ func newFileDigestCatalogerTask(selection file.Selection, hashers []crypto.Hash,
|
||||
result, err := filedigest.NewCataloger(hashers).Catalog(ctx, resolver, coordinates...)
|
||||
|
||||
accessor.WriteToSBOM(func(sbom *sbom.SBOM) {
|
||||
sbom.Artifacts.FileDigests = result
|
||||
mergeInto(&sbom.Artifacts.FileDigests, result)
|
||||
})
|
||||
|
||||
return err
|
||||
@@ -79,7 +79,7 @@ func newFileMetadataCatalogerTask(selection file.Selection, tags ...string) Task
|
||||
result, err := filemetadata.NewCataloger().Catalog(ctx, resolver, coordinates...)
|
||||
|
||||
accessor.WriteToSBOM(func(sbom *sbom.SBOM) {
|
||||
sbom.Artifacts.FileMetadata = result
|
||||
mergeInto(&sbom.Artifacts.FileMetadata, result)
|
||||
})
|
||||
|
||||
return err
|
||||
@@ -105,7 +105,7 @@ func newFileContentCatalogerTask(cfg filecontent.Config, tags ...string) Task {
|
||||
result, err := filecontent.NewCataloger(cfg).Catalog(ctx, resolver)
|
||||
|
||||
accessor.WriteToSBOM(func(sbom *sbom.SBOM) {
|
||||
sbom.Artifacts.FileContents = result
|
||||
mergeInto(&sbom.Artifacts.FileContents, result)
|
||||
})
|
||||
|
||||
return err
|
||||
@@ -131,7 +131,7 @@ func newExecutableCatalogerTask(selection file.Selection, cfg executable.Config,
|
||||
result, err := executable.NewCataloger(cfg).CatalogCtx(ctx, resolver)
|
||||
|
||||
accessor.WriteToSBOM(func(sbom *sbom.SBOM) {
|
||||
sbom.Artifacts.Executables = result
|
||||
mergeInto(&sbom.Artifacts.Executables, result)
|
||||
})
|
||||
|
||||
return err
|
||||
|
||||
@@ -360,6 +360,27 @@ func TestArchiveCataloger_jarReachedThroughALinkIsIdentified(t *testing.T) {
|
||||
assert.Contains(t, s.Artifacts.FileMetadata, manifest)
|
||||
}
|
||||
|
||||
func TestArchiveCataloger_defaultFileSelectionCoversRootJars(t *testing.T) {
|
||||
// with the default owned-by-package selection, a jar at the root is described by the archive task,
|
||||
// so the root file catalogers must run after it or the jar gets no file entries at all
|
||||
dir := t.TempDir()
|
||||
require.NoError(t, os.WriteFile(filepath.Join(dir, "app.jar"), jarBytes(t, "app", "1.0"), 0o644))
|
||||
|
||||
for name, depth := range map[string]int{"feature off": 0, "feature on": 1} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
cfg := DefaultCreateSBOMConfig().
|
||||
WithCatalogerSelection(cataloging.NewSelectionRequest().WithDefaults("java")).
|
||||
WithArchiveConfig(cataloging.DefaultArchiveSearchConfig().WithMaxDepth(depth))
|
||||
s := scanDirWithExclusions(t, dir, cfg)
|
||||
|
||||
require.Equal(t, []string{"|app.jar"}, packageLocations(s, "app"))
|
||||
jar := file.Coordinates{RealPath: "app.jar"}
|
||||
assert.Contains(t, s.Artifacts.FileMetadata, jar)
|
||||
assert.Contains(t, s.Artifacts.FileDigests, jar)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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().
|
||||
|
||||
+14
-10
@@ -211,19 +211,23 @@ func (c *CreateSBOMConfig) makeTaskGroups(src source.Description, exclusions []s
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// combine the user-provided and configured tasks
|
||||
if c.Files.Selection == file.FilesOwnedByPackageSelection {
|
||||
// special case: we need the package info when we are cataloging files owned by packages
|
||||
taskGroups = append(taskGroups, pkgTasks, fileTasks)
|
||||
} else {
|
||||
taskGroups = append(taskGroups, append(pkgTasks, fileTasks...))
|
||||
}
|
||||
|
||||
// the same package and file catalogers run against the contents of every archive, after the scan
|
||||
// root and before relationship and unknowns post-processing
|
||||
archiveTask := task.NewArchiveCatalogerTask(c.Archive, append(slices.Clone(pkgTasks), fileTasks...), exclusions)
|
||||
if archiveTask != nil {
|
||||
taskGroups = append(taskGroups, []task.Task{archiveTask})
|
||||
|
||||
// combine the user-provided and configured tasks
|
||||
switch {
|
||||
case c.Files.Selection == file.FilesOwnedByPackageSelection && archiveTask != nil:
|
||||
// the archive task describes archives at the root too (java leaves them to it), so the root file
|
||||
// catalogers must run after it to see those packages
|
||||
taskGroups = append(taskGroups, pkgTasks, []task.Task{archiveTask}, fileTasks)
|
||||
case c.Files.Selection == file.FilesOwnedByPackageSelection:
|
||||
// special case: we need the package info when we are cataloging files owned by packages
|
||||
taskGroups = append(taskGroups, pkgTasks, fileTasks)
|
||||
case archiveTask != nil:
|
||||
taskGroups = append(taskGroups, append(pkgTasks, fileTasks...), []task.Task{archiveTask})
|
||||
default:
|
||||
taskGroups = append(taskGroups, append(pkgTasks, fileTasks...))
|
||||
}
|
||||
|
||||
// all scope work must be done after all nodes (files and packages) have been cataloged and before the relationship
|
||||
|
||||
Reference in New Issue
Block a user