Files
syft/syft/pkg/cataloger/golang/capabilities.yaml
T
Alex Goodman da745b13e8 feat(golang): add extended-stdlib scope and module patterns for symbol capture (#5154)
* 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>
2026-08-07 12:44:42 +00:00

158 lines
6.8 KiB
YAML

# Cataloger capabilities. See ../README.md for documentation.
configs: # AUTO-GENERATED - config structs and their fields
golang.CatalogerConfig:
fields:
- key: SearchLocalModCacheLicenses
description: SearchLocalModCacheLicenses enables searching for go package licenses in the local GOPATH mod cache.
app_key: golang.search-local-mod-cache-licenses
- key: LocalModCacheDir
description: LocalModCacheDir specifies the location of the local go module cache directory. When not set, syft will attempt to discover the GOPATH env or default to $HOME/go.
app_key: golang.local-mod-cache-dir
- key: SearchLocalVendorLicenses
description: SearchLocalVendorLicenses enables searching for go package licenses in the local vendor directory relative to the go.mod file.
app_key: golang.search-local-vendor-licenses
- key: LocalVendorDir
description: LocalVendorDir specifies the location of the local vendor directory. When not set, syft will search for a vendor directory relative to the go.mod file.
app_key: golang.local-vendor-dir
- key: SearchRemoteLicenses
description: SearchRemoteLicenses enables downloading go package licenses from the upstream go proxy (typically proxy.golang.org).
app_key: golang.search-remote-licenses
- key: Proxies
description: Proxies is a list of go module proxies to use when fetching go module metadata and licenses. When not set, syft will use the GOPROXY env or default to https://proxy.golang.org,direct.
app_key: golang.proxy
- key: NoProxy
description: NoProxy is a list of glob patterns that match go module names that should not be fetched from the go proxy. When not set, syft will use the GOPRIVATE and GONOPROXY env vars.
app_key: golang.no-proxy
- key: CaptureSymbols
description: CaptureSymbols controls extracting function symbols from the binary symbol table (pclntab). Valid values are "none" (disabled), "stdlib" (only the synthetic stdlib package), "extended-stdlib" (stdlib plus every module under golang.org/x/), and "all" (all module packages plus stdlib).
app_key: golang.capture-symbols
- key: CaptureSymbolsModules
description: 'CaptureSymbolsModules is a list of glob patterns (doublestar syntax, where ** crosses path separators and * does not) matched against go module paths. Matching modules get symbols in addition to whatever CaptureSymbols selects, so this can only widen the selection and never narrow it. It has no effect under the "none" scope. A trailing major version suffix is not part of a module''s identity, so a pattern matches with or without it: both "github.com/foo/bar" and "github.com/foo/*" select "github.com/foo/bar/v2". A pattern that spells out a suffix selects only that major version.'
app_key: golang.capture-symbols-modules
catalogers:
- ecosystem: go # MANUAL
name: go-module-binary-cataloger # AUTO-GENERATED
type: generic # AUTO-GENERATED
source: # AUTO-GENERATED
file: syft/pkg/cataloger/golang/cataloger.go
function: NewGoModuleBinaryCataloger
config: golang.CatalogerConfig # AUTO-GENERATED
selectors: # AUTO-GENERATED
- binary
- directory
- go
- golang
- gomod
- image
- installed
- language
- package
parsers: # AUTO-GENERATED structure
- function: parseGoBinary
detector: # AUTO-GENERATED
method: mimetype # AUTO-GENERATED
criteria: # AUTO-GENERATED
- application/x-executable
- application/x-mach-binary
- application/x-elf
- application/x-sharedlib
- application/vnd.microsoft.portable-executable
- application/x-executable
metadata_types: # AUTO-GENERATED
- pkg.GolangBinaryBuildinfoEntry
package_types: # AUTO-GENERATED
- go-module
purl_types: # AUTO-GENERATED
- golang
json_schema_types: # AUTO-GENERATED
- GoModuleBuildinfoEntry
capabilities: # MANUAL - preserved across regeneration
- name: license
default: false
conditions:
- when:
SearchLocalModCacheLicenses: true
value: true
- when:
SearchRemoteLicenses: true
value: true
- name: dependency.depth
default:
- direct
- indirect
- name: dependency.edges
default: flat
- name: dependency.kinds
default:
- runtime
- dev
- name: package_manager.files.listing
default: false
- name: package_manager.files.digests
default: false
- name: package_manager.package_integrity_hash
default: true
evidence:
- GolangBinaryBuildinfoEntry.H1Digest
- ecosystem: go # MANUAL
name: go-module-file-cataloger # AUTO-GENERATED
type: generic # AUTO-GENERATED
source: # AUTO-GENERATED
file: syft/pkg/cataloger/golang/cataloger.go
function: NewGoModuleFileCataloger
config: golang.CatalogerConfig # AUTO-GENERATED
selectors: # AUTO-GENERATED
- declared
- directory
- go
- golang
- gomod
- language
- package
parsers: # AUTO-GENERATED structure
- function: parseGoModFile
detector: # AUTO-GENERATED
method: glob # AUTO-GENERATED
criteria: # AUTO-GENERATED
- '**/go.mod'
metadata_types: # AUTO-GENERATED
- pkg.GolangModuleEntry
- pkg.GolangSourceEntry
package_types: # AUTO-GENERATED
- go-module
purl_types: # AUTO-GENERATED
- golang
json_schema_types: # AUTO-GENERATED
- GoModuleEntry
- GoSourceEntry
capabilities: # MANUAL - preserved across regeneration
- name: license
default: false
conditions:
- when:
SearchLocalModCacheLicenses: true
value: true
- when:
SearchRemoteLicenses: true
value: true
- name: dependency.depth
default:
- direct
- indirect
- name: dependency.edges
default: flat
- name: dependency.kinds
default:
- runtime
- dev
- name: package_manager.files.listing
default: false
- name: package_manager.files.digests
default: false
- name: package_manager.package_integrity_hash
default: true
evidence:
- GolangModuleEntry.H1Digest
- GolangSourceEntry.H1Digest