Commit Graph
12 Commits
Author SHA1 Message Date
Alex Goodman 99723d91dd fix: don't split real paths on !/ in LocalPath and ContainerPath
`LocalPath` searched `FullNestedPath()` for the last `!/`, which is just `RealPath` for a file not in
an archive. A host file like `/data/Hello!/world.txt` came back as `/world.txt`, so lookups and
exclusions ran against the wrong path even with nested cataloging off. `ContainerPath` had the same
problem when `FullPath` was set to `RealPath`.

Both now cut `RealPath` off first and only look for a separator in the entry chain after it, which
can't contain `!/` since entry names with it are refused.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-10-21 11:23:34 -04:00
Keith Zantow a1f7c52d89 fix: unknowns, better full vs local path handling
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2026-10-20 11:15:17 -04:00
Keith Zantow 3e4b036e22 fix: keep RealPath as top-level, use FullPath and utility functions FullNestedPath, LocalPath, Path
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2026-10-19 15:44:37 -04:00
Alex Goodman b735b615f0 fix: name nested files in SPDX by their archive chain
SPDX wrote `FileName` from `RealPath` only, so two archives' `META-INF/MANIFEST.MF` became two SPDX files with the same name and nothing saying which archive each came from. Worse, a consumer reading just the name would take a nested file for one at that path in the scan root.

- a file inside an archive is now named by its full chain, using the same `:` convention and escaping as `ArchivePath` / java's `VirtualPath`: `app.war:WEB-INF/lib/a.jar:META-INF/MANIFEST.MF`
- `FileComment` gains an `archivePath: ...` line (next to the existing `layerID: ...`, one per line), so decoding recovers `ArchivePath` and the entry's own `RealPath` without guessing where the chain ends
- files outside archives are unchanged

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-09-24 13:40:18 -04:00
Alex Goodman 22edfe66ca fix: link nested java packages to their enclosing jar when nested cataloging is on
the legacy recursion links a nested jar to the jar that holds it: a `DEPENDENCY_OF` edge from inner to outer, and `JavaArchive.Parent` on the inner package. Inside an extracted archive java called `parse(ctx, nil)`, so both went away as soon as the feature was on. What replaced them was `file CONTAINS package`, which SPDX and CycloneDX drop, so those formats lost all war-to-jar structure.

- `archive.Traversal` gains `Parent` and `Packages` (the packages found describing that archive, filled in by the task after its sub-pipeline runs)
- java picks the enclosing jar's main package from the parent traversal (the one whose virtual path is the archive's own; pom-derived aux packages carry a suffixed one) and passes it to `parse`, then sets `Parent` the same way the legacy path does

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-09-24 13:36:52 -04:00
Alex Goodman 9d820c6d94 fix: only look up owned-by-package files in the resolver's own frame
with `FilesOwnedByPackageSelection` the file catalogers take every package location in the SBOM and look it up by `RealPath` in the resolver they were given. Inside an archive, the java package's location is the archive itself *in its parent's frame* (`WEB-INF/lib/dep.jar`), so the sub-pipeline looked that path up inside `dep.jar`'s own resolver: a miss, or an unrelated same-named entry by coincidence. At the root, coordinates from inside archives were looked up against the scan root the same way.

`coordinatesForSelection` now keeps only coordinates whose `ArchivePath` matches the current frame (the traversal's `ContentsArchivePath()`, or blank at the root).

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-09-24 13:30:33 -04:00
Alex Goodman 81ee189bf4 fix: bound total decompression under each top-level archive
the limiter bounds what's held *at once*, and each archive gives its bytes back when it's released. So a recursive bomb (42.zip shape) never trips a limit: every level fits on its own, and the scan just runs for effectively forever. Capping each archive at N× its own size wouldn't help either, since every level of such a bomb is high-ratio, so the work still grows about N-fold per level.

- each top-level archive gets one decompression budget of `max(100 × its size, 1 GiB)`, spent by every archive nested under it at any depth
- the budget is attached to the context when the walk enters a top-level archive, so `Extract` picks it up without a signature change
- once it's spent, the archive being extracted is truncated with a "possible decompression bomb" unknown and the walk moves on. The next top-level archive starts fresh

real trees (a war of jars, a layer of tarballs) expand a few times over, well under the ratio.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-09-24 13:23:32 -04:00
Alex Goodman f5bac4a026 fix: build ArchivePath from real paths, not access paths
each `ArchivePath` segment came from `loc.Path()`, so it was the link path when an archive was reached through a symlink and the real path otherwise. That depended on how discovery happened to find the archive. The package location said `store/3f9a1c` while the files inside the same jar were recorded under `...:app/lib/json-simple-1.1.1.jar`, so a consumer couldn't join a package to its files by prefix.

The chain for extracted files is now built from `RealPath`. `Traversal.Location` still carries the access path, so java's name check and `VirtualPath` metadata behave the same as before. The field comment and schema now say every segment has links resolved.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-09-24 11:26:38 -04:00
Alex Goodman eec86cf88d fix: escape % in ArchivePath segments
`:` was escaped as `%3A`, but `%` itself wasn't, so an entry named `a:b.jar` and one named `a%3Ab.jar` got the same `ArchivePath`. Their contents then collide in `FileMetadata` / `FileDigests` (last writer wins) and share artifact IDs.

`%` is now escaped as `%25` before `:`, which makes the encoding injective. The encoding is documented on `Coordinates.ArchivePath` and in the schema.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-09-24 11:23:54 -04:00
Keith Zantow 47cafae01b chore: simplify and cleanup
Signed-off-by: Keith Zantow <keith.zantow@anchore.com>
2026-09-22 00:23:36 -04:00
Keith Zantow 53cd4254e4 chore: revert custom index in favor of key_Split
Signed-off-by: Keith Zantow <keith.zantow@anchore.com>
2026-09-20 11:22:10 -04:00
Keith Zantow 8c0d3747ce feat: initial recursive archive cataloging impl
Signed-off-by: Keith Zantow <keith.zantow@anchore.com>
2026-09-10 08:45:36 -04:00