The decompression rule only matched the stdlib constructors, so the two
cataloger sites that decompress through mholt/archives went unreported while
being exactly as unbounded. Matches OpenReader on an archives.Decompressor,
which picks up both.
Also notes in the report text that a byte limit bounds the input and not what
the consumer retains. Measured on the mtree parser: 16MB of newlines, well
inside a 64MB byte cap, cost 8GB of peak heap, because the parser keeps an
object per line. A site can satisfy this rule and still OOM.
Worth knowing for the next rule: a type filter that fails to resolve takes the
whole rule set down with "used Run() with an empty rule set" rather than just
skipping that rule. Type.Is on an interface does that; Type.Implements with an
m.Import is what works.
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Four rules covering the bug classes behind a batch of parser hardening work:
allocations sized from a header field, decompression with no ceiling, bounds
checks that wrap on unsigned operands, and reads that report end-of-file as
success.
This currently fails with 19 findings, all triaged. Every real one has a fix in
flight on a sibling branch, so this should land last.
Suppressions are deliberately left out for now. Several sites keep firing once
correctly fixed, mostly because the decompression rule flags a constructor and
cannot see the limit applied on the next line. That is a reason to refine the
rule rather than bulk-add nolints.
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
jackson-mapper-asl, jackson-core-asl, and their sibling artifacts
(jackson-jaxrs, jackson-xc, jackson-smile) predate the convention of
embedding META-INF/maven/.../pom.properties in the jar (they were
built with Ant before ~2014). With no POM metadata to read, syft's
groupIDFromJavaMetadata falls through to using the artifact name
itself as the group ID, e.g.
pkg:maven/jackson-mapper-asl/jackson-mapper-asl@1.9.13
instead of the correct
pkg:maven/org.codehaus.jackson/jackson-mapper-asl@1.9.13
(confirmed against the published POM on Maven Central for all five
artifacts). Because the generated purl's namespace doesn't match the
vulnerability database's namespace for these packages, this causes
false negatives in downstream scanning (e.g. Grype cannot match known
CVEs such as CVE-2019-10202 against jackson-mapper-asl).
Add the five artifacts to DefaultArtifactIDToGroupID, the same known-
package-list fallback already used for other jars with incomplete
metadata (e.g. the existing ant-*, spring-ldap* entries).
Fixes#4598
Signed-off-by: ankit090701 <ankitanku090701@gmail.com>
* feat(golang): add extended-stdlib scope and include patterns for symbol capture
`golang.capture-symbols` decides how much symbol data lands in the SBOM for grype's reachability analysis. It's `none`, `stdlib`, or `all` today, and the useful middle is missing: `stdlib` stops at the standard library, `all` multiplies SBOM size.
A new `extended-stdlib` configurable covers stdlib plus everything under `golang.org/x/`:
```yaml
golang:
capture-symbols: extended-stdlib
```
Also, a new `capture-symbols-include` configurable for modules that are noisy in your binaries but not everyone's. It's unioned with whatever the scope selects, so it only ever widens:
```yaml
golang:
capture-symbols: extended-stdlib
capture-symbols-include:
- github.com/klauspost/**
```
Patterns are standard doublestar globs, which matters because module paths carry `/v2`-style suffixes:
```yaml
golang:
capture-symbols-include:
- github.com/klauspost/* # compress, but not compress/v2
- github.com/klauspost/** # both
- k8s.io/client-go # exact match only
```
Ordering is `none` < `stdlib` < `extended-stdlib` < `all`. The existing three values
and the `none` default are unchanged, and the include list is inert under `none`.
Presets compile into glob lists internally, so a single matcher answers "does this
module get symbols" instead of a preset branch sitting next to a separate glob branch.
An unrecognized `capture-symbols` value still falls back to `none`, but warns now
instead of doing it silently. A malformed include pattern warns and gets skipped.
One thing worth a look beyond the feature: the `Symbols` field description in the JSON
schema was wrong after this (it claimed only `all` and `stdlib` populate anything), and
that description lives in the already-published `16.1.10`. Rather than bump a version for
a sentence, `16.1.10` is amended in place and `schema/json/README.md` grows an explicit
exception for description-only changes: descriptions only, no shape change of any kind,
`$id` unchanged. Anything else still needs a bump. Happy to split that into its own PR if
you'd rather review the policy separately.
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
* refactor(golang): rename capture-symbols-include to capture-symbols-modules
The key's entries are go module paths, and `-include` sitting next to `capture-symbols` reads as plausibly taking symbol or package names instead. Those spellings parse and match nothing, which is quieter than the confusion `-include` was picked to avoid, so the name now says what the list holds.
`golang.CatalogerConfig.CaptureSymbolsModules` and `WithCaptureSymbolsModules` rename with it. Nothing behavioral changes; the key is new in this PR so there is no compatibility surface.
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
* feat(golang): match capture-symbols-modules across major version suffixes
`github.com/anchore/*` covered `github.com/anchore/syft` and silently stopped covering it the day it became `github.com/anchore/syft/v2`. The config keeps parsing, nothing warns, and symbols quietly go missing from the SBOM. Exact paths had the same hole: `github.com/klauspost/compress` did not cover `compress/v2` either, so no spelling short of `**` survived a major bump.
A major version suffix is part of a module's path but not part of its identity, so patterns are now matched against the module path both with and without it, using `module.SplitPathVersion` from `golang.org/x/mod` (already a direct dep, already used in this package for `PseudoVersion`).
```yaml
golang:
capture-symbols-modules:
- github.com/klauspost/* # compress and compress/v2
- github.com/klauspost/compress # same module at every major version
- github.com/klauspost/compress/v2 # v2 alone
```
Only a trailing suffix is a version, which is Go's own rule. In `github.com/anchore/syft/v2/thing` the `v2` is an ordinary path element naming a major subdirectory a nested module lives in, so it stays literal and `github.com/anchore/**/thing` is how you reach it. `/v0` and `/v1` are not valid suffixes and are left alone.
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
---------
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
The two "RACE is unset" cases only skipped the t.Setenv call, so they
inherited whatever RACE was in the environment. Running `make test` with
RACE=false exported job-wide flipped the CI-default case and failed.
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
with a cold fixture cache the integration suite builds and saves 18 docker
images across 36 sequential tests, which walks past `go test`'s default 10m
timeout and takes the fixture cache rebuild down with it. that suite now runs
`go test` directly with `-timeout=30m` (gotest.Tasks() has no timeout option),
plus `-count=1` since the built fixtures are the side effect we're actually
after and a test cache hit would skip producing them.
also adds `RACE` as one switch for the race detector across every suite:
- `RACE=false make test` drops `-race` from unit + integration and skips the
race smoke, worth doing on a cache rebuild where the wall clock is all
docker builds anyway
- `RACE=true` forces it on locally
- unset behaves as before: on in CI, off locally and on windows
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
---------
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
* report each hardlink as its own file when scanning images
image scans previously collapsed a set of hardlinks onto a single file, so only
one path per inode showed up in results. dir scans report every hardlink path,
which made image vs dir SBOMs of the same filesystem diverge (and produce
different SPDX `packageVerificationCode` values for packages that own hardlinked
files).
now both image resolvers (squash and all-layers) surface each hardlink at its
own path as a regular file bound to the target's content, matching dir scans.
user-facing impact:
- SBOMs for images containing hardlinks will list more `file` entries
- SPDX `packageVerificationCode` values change for affected packages, now
matching the equivalent `dir:` scan
- adds `file.NewVirtualLocationFromImage` to the public API
fixes#5019
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
* fix busybox test assertion
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
---------
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
parseErlangString advances past a backslash escape and then checks
len(data) >= *i before reading the escaped byte. That condition is
almost always true (it only turns false once *i runs off the end),
so the intended out-of-range guard fires on the very first escape
character it sees instead of only at EOF. Any rebar.lock or OTP
resource file containing a backslash in a quoted string (a Windows
git path, an escaped quote, anything) fails to parse and the whole
file, and every package in it, gets dropped.
Flip the comparison to *i >= len(data) so the guard only trips when
the escape is genuinely truncated, and add a regression test for a
string with an escaped quote.
Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
* Prevent duplicate Go packages after source replacement resolution
Source analysis already applies module replacements through go/packages. Avoid synthesizing the same replacement again from go.mod while retaining fallback synthesis for modules that source analysis did not resolve.
Constraint: Preserve unimported and local-path replacement cataloging.
Rejected: Deduplicate only during final assembly | That retains redundant license lookup and ambiguous metadata ownership.
Confidence: high
Scope-risk: narrow
Directive: Keep go.mod fallback packages limited to modules absent from source analysis.
Tested: Focused replacement regression, related Go module parser tests, go vet, gofmt, and diff checks.
Not-tested: Docker-backed full cataloger fixtures; local root storage was exhausted by image generation.
Signed-off-by: ychampion <ychampion@users.noreply.github.com>
* Keep replacement fixtures with the Go module test data
Constraint: The maintainer reserves internal/gotestdata for fixtures that need special Go tooling discovery.
Rejected: Leave this fixture in gotestdata | The regression opens its module explicitly and does not need the special location.
Confidence: high
Scope-risk: narrow
Directive: Use internal/gotestdata only when a fixture must avoid Go testdata discovery rules.
Tested: replacement regression repeated 10 times; Go module parser table; go vet for the Go cataloger; gofmt; diff checks.
Not-tested: Full cataloger package; three unrelated parser fixtures fail identically on exact prior head in this environment.
Signed-off-by: ychampion <ychampion@users.noreply.github.com>
---------
Signed-off-by: ychampion <ychampion@users.noreply.github.com>
Co-authored-by: ychampion <ychampion@users.noreply.github.com>
* Add multi-platform OCI image support
Signed-off-by: Jason Paulos <jasonpaulos@users.noreply.github.com>
* Reduce calls to PrepareMultiplatformFixtureImage in TestMultiPlatformOCIImageSelection
Signed-off-by: Jason Paulos <jasonpaulos@users.noreply.github.com>
* Use smaller image for testing & update stereoscope fork
Signed-off-by: Jason Paulos <jasonpaulos@users.noreply.github.com>
* bump to stereoscope@main after 548 merge
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
---------
Signed-off-by: Jason Paulos <jasonpaulos@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>