mirror of
https://github.com/anchore/syft.git
synced 2026-11-04 08:26:38 +01:00
feat: initial recursive archive cataloging impl
Signed-off-by: Keith Zantow <keith.zantow@anchore.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
|
||||
// Traversal describes one level of archive nesting during recursive archive cataloging. The archive
|
||||
// cataloger task places one on the context before running the cataloger sub-pipeline against an
|
||||
// archive's contents, so ecosystem catalogers (e.g. java) can reconstruct nesting-aware identity
|
||||
// such as colon-delimited virtual paths (e.g. "app.war:WEB-INF/lib/dep.jar") without owning the
|
||||
// recursion themselves.
|
||||
type Traversal struct {
|
||||
// Location is the archive file's location within its parent filesystem.
|
||||
Location file.Location
|
||||
|
||||
// VirtualPath is the colon-delimited chain of archive paths from the scan root to this archive,
|
||||
// e.g. "app.war:WEB-INF/lib/dep.jar".
|
||||
VirtualPath string
|
||||
|
||||
// FileSystemID is the identifier of the filesystem the archive file itself lives on (a container
|
||||
// image layer digest, or empty for a directory source), inherited unchanged down the nesting
|
||||
// chain. The nesting chain is carried by VirtualPath, not by this field.
|
||||
FileSystemID string
|
||||
|
||||
// Depth is 1 for an archive found directly in the scan source, incrementing per nesting level.
|
||||
Depth int
|
||||
|
||||
// Digests are the digests of the archive file itself. They are carried here because they are a
|
||||
// property of the file and not of its contents: a cataloger running against an archive's extracted
|
||||
// filesystem cannot compute them, since the archive is not inside itself. Taken once by the
|
||||
// extraction, which already has the bytes in hand.
|
||||
Digests []file.Digest
|
||||
|
||||
// Parent is the traversal for the containing archive; nil at depth 1.
|
||||
Parent *Traversal
|
||||
}
|
||||
|
||||
// VirtualPathOf returns the colon-delimited virtual path for an entry within this archive. It is
|
||||
// nil-safe: with no traversal the entry path is returned unchanged, matching non-nested behavior.
|
||||
// The entry path's leading slash is trimmed so chains match the historical java cataloger format,
|
||||
// which joins slash-less zip entry names onto the containing archive's path.
|
||||
func (t *Traversal) VirtualPathOf(entryPath string) string {
|
||||
if t == nil {
|
||||
return entryPath
|
||||
}
|
||||
entryPath = strings.ReplaceAll(entryPath, ":", "%3A")
|
||||
if t.VirtualPath == "" {
|
||||
return entryPath
|
||||
}
|
||||
return t.VirtualPath + ":" + strings.TrimPrefix(entryPath, "/")
|
||||
}
|
||||
|
||||
type limiterCtxKey struct{}
|
||||
|
||||
// WithLimiter returns a context carrying the scan's archive limiter, so a cataloger running within
|
||||
// the recursive walk can read the scan's live draw on the memory and disk budgets (Limiter.InUse) -
|
||||
// the same totals the limits are enforced against. Carried on the context rather than copied onto
|
||||
// each Traversal so there is one source of truth for the charge, not a snapshot per level.
|
||||
func WithLimiter(ctx context.Context, l *Limiter) context.Context {
|
||||
return context.WithValue(ctx, limiterCtxKey{}, l)
|
||||
}
|
||||
|
||||
// LimiterFromContext returns the scan's archive limiter, or nil when the current pass is not running
|
||||
// within the recursive archive walk.
|
||||
func LimiterFromContext(ctx context.Context) *Limiter {
|
||||
l, _ := ctx.Value(limiterCtxKey{}).(*Limiter)
|
||||
return l
|
||||
}
|
||||
|
||||
type traversalCtxKey struct{}
|
||||
|
||||
// WithTraversal returns a context carrying the given archive traversal.
|
||||
func WithTraversal(ctx context.Context, t *Traversal) context.Context {
|
||||
return context.WithValue(ctx, traversalCtxKey{}, t)
|
||||
}
|
||||
|
||||
// TraversalFromContext returns the archive traversal on the context, or nil when the current
|
||||
// cataloging pass is not running within an archive.
|
||||
func TraversalFromContext(ctx context.Context) *Traversal {
|
||||
t, _ := ctx.Value(traversalCtxKey{}).(*Traversal)
|
||||
return t
|
||||
}
|
||||
Reference in New Issue
Block a user