fix: report archives left unexplored at the nested depth limit

with nested cataloging on, java stops recursing into jars itself (the task owns recursion) and its own "nested archives not cataloged" unknown is suppressed. The task then just returned at the depth bound. So `MaxDepth: 1` on a war silently found fewer jars than leaving the feature off, and nothing in the SBOM said so.

at the bound, every archive that sits there (by content sniff) is now recorded as a "nested archive not cataloged: the nested archive depth limit was reached" unknown. The CLI description for `nested-archive-max-depth` notes that it replaces java's unbounded jar-in-jar recursion.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman
2026-09-24 13:24:29 -04:00
parent 81ee189bf4
commit fe4fdc786c
3 changed files with 14 additions and 1 deletions
+2 -1
View File
@@ -26,7 +26,8 @@ note: enabling this may result in a performance impact since all discovered comp
note: this only applies to the java package cataloger, and is ignored when nested-archive-max-depth is not 0 (every archive is searched)`)
descriptions.Add(&o.ExcludeBinaryOverlapByOwnership, `allows users to exclude synthetic binary packages from the sbom
these packages are removed if an overlap with a non-synthetic package is found`)
descriptions.Add(&o.NestedArchiveMaxDepth, `maximum depth to recursively catalog nested archives (0 = disabled, -1 = as deep as 16 levels)`)
descriptions.Add(&o.NestedArchiveMaxDepth, `maximum depth to recursively catalog nested archives (0 = disabled, -1 = as deep as 16 levels)
note: when enabled this replaces the java cataloger's own unbounded jar-in-jar recursion, so archives deeper than this are reported as unknowns rather than cataloged`)
descriptions.Add(&o.NestedArchiveMaxMemoryBytes, `maximum bytes of nested archive content held in memory at once (0 = default, -1 = unbounded)`)
descriptions.Add(&o.NestedArchiveMaxDiskBytes, `maximum bytes of nested archive content on disk at once (0 = default, -1 = unbounded)`)
}
+5
View File
@@ -270,6 +270,11 @@ func Test_mixedFamilyNesting_depthCountsLevelsNotFamilies(t *testing.T) {
}
_, ok := s.Artifacts.FileMetadata[innermost]
assert.True(t, ok, "the undescended archive must still be recorded as a file at %s", coordKey(innermost))
// and what was left unexplored is said out loud, not silently dropped
reasons := s.Artifacts.Unknowns[innermost]
require.Len(t, reasons, 1, "unknowns: %v", s.Artifacts.Unknowns)
assert.Contains(t, reasons[0], "depth limit was reached")
})
}
}
+7
View File
@@ -145,6 +145,13 @@ func (c *archiveCataloger) catalog(ctx context.Context, resolver file.Resolver,
maxDepth = unboundedArchiveDepth
}
if depth >= maxDepth {
// java's own recursion is off while this task runs, so an archive left here is otherwise lost
// without a trace
for _, candidate := range c.discoverArchives(resolver) {
if candidate.sniffedAsArchive {
recordArchiveUnknown(builder, candidate.location.Coordinates, "nested archive not cataloged: the nested archive depth limit was reached")
}
}
return nil
}
var errs error