Compare commits

..
Author SHA1 Message Date
fa02ff2d26 feat(executable): capture GNU ELF build IDs (#5426)
* feat(executable): capture GNU ELF build IDs

Capture GNU ELF build IDs in Syft JSON so consumers can correlate
otherwise unidentified binaries with known artifacts or build records.

Read GNU build-ID notes from .note.gnu.build-id, with a 64 KiB read limit.
Validate the note owner and type before recording the identifier.

Add focused extraction and JSON round-trip tests and update the schema.

Signed-off-by: Mario Corchero <mcorcherojim@bloomberg.net>

* chore: bump JSON schema to 16.1.13 for executable identifiers

16.1.12 landed on main for coordinate fullPath, so the identifiers
addition moves to the next version.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* feat(executable): capture go build IDs from .note.go.buildid

The go linker only writes a GNU build ID with -B or when linking
externally, so most pure-Go binaries had no identifier. Every go ELF
carries .note.go.buildid, captured as kind `go-build-id` in the form
`go tool buildid` prints.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* docs(executable): describe identifiers generically

Identifier field docs (and the published schema) now give GNU hex and
Go build IDs as examples instead of stating every value is a GNU build
ID in lowercase hex, so the contract holds as more kinds are added.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* fix(executable): keep identifier notes inside elfutil bounds

Register `.note.gnu.build-id` and `.note.go.buildid` in elfutil's
sectionsReadByName as that list asks, and never open a compressed
identifier note. Real ones are SHF_ALLOC and cannot be compressed, so
this drops the only decompression path into these reads.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* test(executable): check identifiers from real linker output

Cross-compiles a tiny go program with `-B` so the test sees a GNU
build ID and a go build ID written by an actual linker and read through
the cataloger entrypoint.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Mario Corchero <mcorcherojim@bloomberg.net>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Mario Corchero <mcorcherojim@bloomberg.net>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-11-04 22:42:03 +00:00
Alex GoodmanandWill Murphy fd712ee71a perf: build lower layer squashes only when a scan reads them (#5492)
* perf: keep only the image squash when scanning with the squashed scope

- stereoscope builds a squashed tree for every layer, each a full copy of the one below, so memory
  grows with layers x files. The squashed scope only ever reads the top one.
- new `GetSourceConfig.WithImageSquashOnly(bool)` (and `sourceproviders.Config` field) reads images
  with stereoscope's `image.WithImageSquashOnly`, scoped to that one read
- the CLI turns it on when `--scope squashed` (the default)
- an image source read this way returns an error from `FileResolver` for `all-layers` and
  `deep-squashed` instead of panicking on the missing layer squashes

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* chore(deps): temporarily pin stereoscope to anchore/stereoscope#731

Replaces stereoscope with the PR head on the contributor fork so this builds. Drop the replace and
bump to a released version once that PR merges.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* chore(deps): bump stereoscope to main for WithImageSquashOnly

Drops the temporary replace to the contributor fork now that anchore/stereoscope#731 has merged.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* revert: drop the squash-only image read and bump stereoscope

stereoscope is replacing `image.WithImageSquashOnly` with lazy layer squashes, where every layer keeps a usable squash. That removes the need for `GetSourceConfig.WithImageSquashOnly` and the scope guard in `FileResolver`, so both go.

- bumps stereoscope to `feat/lazy-layer-squashes` (anchore/stereoscope `43c8f7e`), pending that PR merging

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* perf: build lower layer squashes only when a scan reads them

The image source provider now reads images with `image.WithLazyLayerSquashes`: the image squash is built during the read, and each lower layer's squash only when something reads it. A squashed scan never does, so it skips a full file tree copy per layer.

- squashed scans: faster, much less memory on images with many layers
- `scan`/`attest` with all-layers or deep-squashed stay eager (an internal ctx flag), since eager squashing overlaps with fetching and indexing and is faster when every layer gets read
- library callers going through `syft.GetSource` get lazy for every scope, since the scope isn't known when the image is read. All-layers is still correct, just slower
- no public API change

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* pull in stereoscope@main

Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>
Co-authored-by: Will Murphy <willmurphyscode@users.noreply.github.com>
2026-11-04 15:12:25 -05:00
Tim Olshansky 551442b1bc fix(terraform): generate NVD-style terraform_provider CPEs for terraform lock packages (#5261)
* fix: generate terraform-provider-specific CPEs for terraform lock packages

The terraform-lock-cataloger sets Language to Go, which causes the Go CPE
heuristic to generate application-level CPEs for terraform providers. For
example, registry.terraform.io/grafana/grafana produces the same CPE as
the Grafana application itself, leading grype to flag providers with
unrelated CVEs.

This adds terraform-specific vendor/product candidate functions that
generate CPEs matching the NVD convention for terraform providers
(e.g. terraform-provider-grafana instead of grafana), with terraform
as the target software qualifier.

Signed-off-by: Tim Olshansky <456103+timols@users.noreply.github.com>

* fix: align terraform provider CPEs with NVD terraform_provider convention

NVD records terraform providers with a fixed "terraform_provider" product
and the provider type in target_sw, e.g.
cpe:2.3:a:hashicorp:terraform_provider:*:*:*:*:*:vault:*:*

Generate <namespace>:terraform_provider:<version>:...:<type> instead of
<namespace>:terraform-provider-<type>:<version>:...:terraform, which never
appears in NVD.

Signed-off-by: Tim Olshansky <456103+timols@users.noreply.github.com>

---------

Signed-off-by: Tim Olshansky <456103+timols@users.noreply.github.com>
2026-11-03 22:01:20 -05:00
Guillaume MartyandGuillaume Marty 639de5db64 fix: keep dot-separated pre-release identifiers in Go ldflags versions (#5422)
The ldflags version regexes stopped at the first dot after the patch
number, so v1.28.0-rc.1 was reported as v1.28.0-rc.

Signed-off-by: Guillaume Marty <279286709+LemonCondor@users.noreply.github.com>
Co-authored-by: Guillaume Marty <279286709+LemonCondor@users.noreply.github.com>
2026-11-03 10:20:09 -05:00
Juan 5ec416cb24 fix: do not generate CPEs for msrc-kb packages (#5510)
A msrc-kb package's name is an MSRC product ID and its version a KB
number, so the generic generator produced CPEs such as
cpe:2.3:a:12437:12437:935509:*:*:*:*:*:*:*. A KB is a patch rather than
a product and has no CPE representation; these packages are matched
against MSRC data by name and version. Skip generation for them, as is
already done for ML model packages. The dictionary lookup already
returns nothing for this type.

Signed-off-by: juanjsebgarcia <github@juangarcia.co.uk>
2026-11-02 15:52:38 -05:00
anchore-oss-update-botandanchore-oss-update-bot 173055c39e chore(deps): update anchore dependencies (#5479)
Signed-off-by: anchore-oss-update-bot <anchore-oss-update-bot@users.noreply.github.com>
Co-authored-by: anchore-oss-update-bot <anchore-oss-update-bot@users.noreply.github.com>
2026-11-02 16:30:25 +00:00
anchore-oss-update-botandanchore-oss-update-bot f974ef598c chore(deps): update tool versions (#5509)
Signed-off-by: anchore-oss-update-bot <anchore-oss-update-bot@users.noreply.github.com>
Co-authored-by: anchore-oss-update-bot <anchore-oss-update-bot@users.noreply.github.com>
2026-11-01 10:19:06 +00:00
dependabot[bot] e6813ba7b6 chore(deps): bump github.com/github/go-spdx/v2 from 2.7.1 to 2.8.0 (#5502)
Bumps [github.com/github/go-spdx/v2](https://github.com/github/go-spdx) from 2.7.1 to 2.8.0.
- [Release notes](https://github.com/github/go-spdx/releases)
- [Commits](https://github.com/github/go-spdx/compare/v2.7.1...v2.8.0)

---
updated-dependencies:
- dependency-name: github.com/github/go-spdx/v2
  dependency-version: 2.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-30 13:45:16 +00:00
dependabot[bot] 1238ace393 chore(deps): bump github.com/go-jose/go-jose/v4 from 4.1.5 to 4.1.6 (#5504)
Bumps [github.com/go-jose/go-jose/v4](https://github.com/go-jose/go-jose) from 4.1.5 to 4.1.6.
- [Release notes](https://github.com/go-jose/go-jose/releases)
- [Commits](https://github.com/go-jose/go-jose/compare/v4.1.5...v4.1.6)

---
updated-dependencies:
- dependency-name: github.com/go-jose/go-jose/v4
  dependency-version: 4.1.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-30 13:43:40 +00:00
dependabot[bot] 80ecdfe63f chore(deps): bump github.com/deitch/magic (#5503)
Bumps [github.com/deitch/magic](https://github.com/deitch/magic) from 0.0.0-20230404182410-1ff89d7342da to 1.0.0.
- [Commits](https://github.com/deitch/magic/commits/v1.0.0)

---
updated-dependencies:
- dependency-name: github.com/deitch/magic
  dependency-version: 1.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-30 13:35:51 +00:00
dependabot[bot] 1fa6bf6848 chore(deps): bump github.com/gpustack/gguf-parser-go (#5500)
Bumps [github.com/gpustack/gguf-parser-go](https://github.com/gpustack/gguf-parser-go) from 0.26.4 to 0.27.0.
- [Release notes](https://github.com/gpustack/gguf-parser-go/releases)
- [Commits](https://github.com/gpustack/gguf-parser-go/compare/v0.26.4...v0.27.0)

---
updated-dependencies:
- dependency-name: github.com/gpustack/gguf-parser-go
  dependency-version: 0.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-30 13:29:22 +00:00
dependabot[bot] b0bc371473 chore(deps): bump modernc.org/sqlite from 1.60.1 to 1.61.0 (#5499)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.60.1 to 1.61.0.
- [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.60.1...v1.61.0)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.61.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-30 13:29:00 +00:00
dependabot[bot] d91462b824 chore(deps): bump github.com/gkampitakis/go-snaps from 0.5.23 to 0.5.24 (#5501)
Bumps [github.com/gkampitakis/go-snaps](https://github.com/gkampitakis/go-snaps) from 0.5.23 to 0.5.24.
- [Release notes](https://github.com/gkampitakis/go-snaps/releases)
- [Commits](https://github.com/gkampitakis/go-snaps/compare/v0.5.23...v0.5.24)

---
updated-dependencies:
- dependency-name: github.com/gkampitakis/go-snaps
  dependency-version: 0.5.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-30 13:28:32 +00:00
dependabot[bot] 181b9198c0 chore(deps): bump zizmorcore/zizmor-action from 0.7.1 to 0.8.0 (#5497)
Bumps [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) from 0.7.1 to 0.8.0.
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](https://github.com/zizmorcore/zizmor-action/compare/85b2b9fb8e3325e7a23d7d0a9d7ba5ae0f999e3e...53290badfa369cb0bf7ad16342cb62c2fa47ac7b)

---
updated-dependencies:
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-30 13:27:35 +00:00
dependabot[bot] 4614cf1d85 chore(deps): bump docker/login-action from 4.6.0 to 4.7.0 (#5498)
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.6.0 to 4.7.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/dbcb813823bdd20940b903addbd779551569679f...81c6f93d4bc991e510b342a00b419b3bb4efc5c6)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-30 13:27:21 +00:00
23 changed files with 5581 additions and 100 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ tools:
# used to upload test fixture cache
- name: oras
version:
want: v1.3.5
want: v1.3.6
method: github-release
with:
repo: oras-project/oras
+2 -2
View File
@@ -89,13 +89,13 @@ jobs:
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Login to Docker Hub
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f #v4.6.0
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 #v4.7.0
with:
username: ${{ secrets.ANCHOREOSSWRITE_DH_USERNAME }}
password: ${{ secrets.ANCHOREOSSWRITE_DH_PAT }}
- name: Login to GitHub Container Registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f #v4.6.0
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 #v4.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -25,7 +25,7 @@ jobs:
persist-credentials: false
- name: "Run zizmor"
uses: zizmorcore/zizmor-action@85b2b9fb8e3325e7a23d7d0a9d7ba5ae0f999e3e # v0.7.1
uses: zizmorcore/zizmor-action@53290badfa369cb0bf7ad16342cb62c2fa47ac7b # v0.8.0
with:
# there is a pass/fail gate as a repo ruleset (if there is no ruleset configured then the action will pass by default)
advanced-security: true
+5
View File
@@ -260,6 +260,11 @@ func getSource(ctx context.Context, opts *options.Catalog, userInput string, sou
cfg = cfg.WithDigestAlgorithms(hashers...)
}
if source.ParseScope(opts.Scope) != source.SquashedScope {
// every other scope reads each layer's squash, which is cheaper to build while the image is read
ctx = internal.WithEagerLayerSquashes(ctx)
}
src, err := syft.GetSource(ctx, userInput, cfg)
if err != nil {
return nil, fmt.Errorf("could not determine source: %w", err)
+29 -30
View File
@@ -12,7 +12,7 @@ require (
github.com/acobaugh/osrelease v0.1.0
github.com/adrg/xdg v0.5.3
github.com/anchore/bubbly v0.2.2
github.com/anchore/clio v0.1.1
github.com/anchore/clio v0.1.2
github.com/anchore/fangs v0.1.1
github.com/anchore/go-collections v0.1.1
github.com/anchore/go-homedir v0.1.1
@@ -22,7 +22,7 @@ require (
github.com/anchore/go-sync v0.1.2
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/packageurl-go v0.2.0
github.com/anchore/stereoscope v0.3.5-0.20261030123700-09449eab9587
github.com/anchore/stereoscope v0.4.0
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
github.com/aquasecurity/go-pep440-version v0.0.1
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
@@ -33,14 +33,13 @@ require (
github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/lipgloss v1.1.0
github.com/dave/jennifer v1.7.1
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
github.com/deitch/magic v1.0.0
github.com/diskfs/go-diskfs v1.9.4
github.com/distribution/reference v0.6.0
github.com/dustin/go-humanize v1.1.0
github.com/elliotchance/phpserialize v1.4.0
github.com/facebookincubator/nvdtools v0.1.5
github.com/github/go-spdx/v2 v2.7.1
github.com/gkampitakis/go-snaps v0.5.23
github.com/gkampitakis/go-snaps v0.5.24
github.com/go-git/go-billy/v5 v5.9.2
github.com/go-git/go-git/v5 v5.19.3
github.com/go-test/deep v1.1.2
@@ -52,7 +51,7 @@ require (
github.com/google/licensecheck v0.3.1
github.com/google/uuid v1.6.0
github.com/gookit/color v1.6.3
github.com/gpustack/gguf-parser-go v0.26.4
github.com/gpustack/gguf-parser-go v0.27.0
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-getter v1.8.10
github.com/hashicorp/go-multierror v1.1.1
@@ -69,6 +68,7 @@ require (
github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1
github.com/olekukonko/tablewriter v1.1.5
github.com/opencontainers/go-digest v1.0.0
github.com/pb33f/ordered-map/v2 v2.3.2
github.com/pelletier/go-toml v1.9.5
github.com/quasilyte/go-ruleguard/dsl v0.3.23
github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c
@@ -83,6 +83,7 @@ require (
github.com/spf13/afero v1.15.0
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.12.1
github.com/tailscale/hujson v0.0.0-20260302212456-ecc657c15afd
github.com/ulikunitz/xz v0.5.17
github.com/vbatts/go-mtree v0.7.0
github.com/vifraa/gopom v1.0.0
@@ -95,17 +96,14 @@ require (
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f
golang.org/x/mod v0.42.0
golang.org/x/net v0.61.0
golang.org/x/sys v0.49.0
golang.org/x/time v0.16.0
golang.org/x/tools v0.52.0
modernc.org/sqlite v1.60.1
howett.net/plist v1.0.1
modernc.org/sqlite v1.61.0
)
require (
github.com/pb33f/ordered-map/v2 v2.3.2
github.com/tailscale/hujson v0.0.0-20260302212456-ecc657c15afd
golang.org/x/sys v0.49.0
howett.net/plist v1.0.1
)
require github.com/github/go-spdx/v2 v2.8.0
require (
cel.dev/expr v0.25.2 // indirect
@@ -123,9 +121,9 @@ require (
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29 // indirect
github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0 // indirect
github.com/Microsoft/hcsshim v0.15.0-rc.4 // indirect
github.com/ProtonMail/go-crypto v1.4.1 // indirect
github.com/ProtonMail/go-crypto v1.5.2 // indirect
github.com/STARRY-S/zip v0.2.3 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/agext/levenshtein v1.2.1 // indirect
@@ -181,15 +179,15 @@ require (
github.com/containerd/log/otel v0.1.0 // indirect
github.com/containerd/platforms v1.0.0-rc.5 // indirect
github.com/containerd/plugin v1.1.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.19.0 // indirect
github.com/containerd/ttrpc v1.2.9 // indirect
github.com/containerd/typeurl/v2 v2.3.0 // indirect
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
github.com/containers/ocicrypt v1.3.2 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
github.com/cyphar/filepath-securejoin v0.7.0 // indirect
github.com/docker/cli v29.9.1+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.8 // indirect
github.com/docker/cli v29.9.2+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.10 // indirect
github.com/docker/go-connections v0.8.2 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
@@ -201,7 +199,7 @@ require (
github.com/felixge/fgprof v0.9.5 // indirect
github.com/felixge/httpsnoop v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.15 // indirect
github.com/gabriel-vasile/mimetype v1.4.16 // indirect
github.com/gkampitakis/ciinfo v0.3.4 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-jose/go-jose/v4 v4.1.6 // indirect
@@ -210,7 +208,7 @@ require (
github.com/go-restruct/restruct v1.2.0-alpha // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/google/go-intervals v0.0.2 // indirect
github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 // indirect
github.com/google/pprof v0.0.0-20261016150608-1facf8f91b50 // indirect
github.com/google/s2a-go v0.1.10 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.22 // indirect
github.com/googleapis/gax-go/v2 v2.24.1 // indirect
@@ -224,7 +222,7 @@ require (
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/klauspost/pgzip v1.2.7 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
@@ -232,8 +230,8 @@ require (
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.24 // indirect
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 // indirect
github.com/mattn/go-runewidth v0.0.27 // indirect
github.com/mattn/go-sqlite3 v1.14.48 // indirect
github.com/mattn/go-runewidth v0.0.31 // indirect
github.com/mattn/go-sqlite3 v1.14.52 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/miekg/pkcs11 v1.1.2 // indirect
github.com/mikelolasagasti/xz v1.0.1 // indirect
@@ -256,7 +254,7 @@ require (
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/ncruces/go-strftime v1.1.0 // indirect
github.com/nwaples/rardecode/v2 v2.4.1 // indirect
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
github.com/olekukonko/errors v1.2.0 // indirect
@@ -283,7 +281,7 @@ require (
github.com/sahilm/fuzzy v0.1.1 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.11.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sigstore/fulcio v1.8.7 // indirect
github.com/sigstore/fulcio v1.8.8 // indirect
github.com/sigstore/protobuf-specs v0.5.2 // indirect
github.com/sigstore/sigstore v1.10.11 // indirect
github.com/sirupsen/logrus v1.10.2 // indirect
@@ -307,9 +305,10 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/varlink/go v0.4.1-0.20261015173642-c935be0c53f7 // indirect
github.com/vbatts/tar-split v0.12.3 // indirect
github.com/vbauerster/cupwriter v0.0.4 // indirect
github.com/vbauerster/mpb/v8 v8.14.0 // indirect
github.com/vbauerster/cupwriter v0.0.5 // indirect
github.com/vbauerster/mpb/v8 v8.16.2 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
@@ -326,8 +325,8 @@ require (
go.opentelemetry.io/otel/sdk v1.46.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.46.0 // indirect
go.opentelemetry.io/otel/trace v1.46.0 // indirect
go.podman.io/image/v5 v5.41.2 // indirect
go.podman.io/storage v1.64.2 // indirect
go.podman.io/image/v5 v5.42.0 // indirect
go.podman.io/storage v1.65.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/crypto v0.58.0 // indirect
golang.org/x/oauth2 v0.37.0 // indirect
@@ -343,7 +342,7 @@ require (
google.golang.org/grpc v1.84.0 // indirect
google.golang.org/protobuf v1.36.12 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
modernc.org/libc v1.77.1 // indirect
modernc.org/libc v1.79.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.12.1 // indirect
)
+58 -56
View File
@@ -99,15 +99,15 @@ github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lpr
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29 h1:0kQAzHq8vLs7Pptv+7TxjdETLf/nIqJpIB4oC6Ba4vY=
github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29/go.mod h1:ZWa7ssZJT30CCDGJ7fk/2SBTq9BIQrrVjrcss0UW2s0=
github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0 h1:71VU8kW/LCxJkx41+YYys1EgQO+AUnPa1TrxTSyYUCU=
github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0/go.mod h1:ma0QpxizD4fyyzJ1C7MIblymTD2Nxz5Mho/3CepwIZg=
github.com/Microsoft/hcsshim v0.15.0-rc.4 h1:aZFX4LH0S20Lgjq0wG61StIClj7im4yzrxIClkaR8Z8=
github.com/Microsoft/hcsshim v0.15.0-rc.4/go.mod h1:BA9CBztgu4h/6Jsvo1O1M4qjWw09PoYpaEYgexPE578=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM=
github.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=
github.com/ProtonMail/go-crypto v1.5.2 h1:cucYnvqcY7UOXVD//mSyjeaPY0SSN3v5cDkYPxumINk=
github.com/ProtonMail/go-crypto v1.5.2/go.mod h1:/RaSu30DaKO4RY+XdV/ACcCcZkGr7AhUIduq5sjzzCo=
github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4=
github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk=
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
@@ -126,8 +126,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anchore/bubbly v0.2.2 h1:53JHRlpaNZjMcUYdz7n1U7+kOhy0zsJv9gpGEXvTcz8=
github.com/anchore/bubbly v0.2.2/go.mod h1:M4twoFkczlfuNdU8QV7oQjVJwPbxdUWRMfKydcLba0U=
github.com/anchore/clio v0.1.1 h1:9bkYnaFbpT0J3G0qSHyQqa/lpK5zV0C9Gtgh82H/jj0=
github.com/anchore/clio v0.1.1/go.mod h1:CFPIopJlakJbBpKtAL/EPpj4W9hgBO7PfFc8N2FAtlE=
github.com/anchore/clio v0.1.2 h1:kCWNUkJsRJ5A103fFSLG+CSqIP9bOIFX2X5GEnup0HM=
github.com/anchore/clio v0.1.2/go.mod h1:LqoM9TUMDolUMaPV4hslLvuooqIjpTN8J7V/rBqk/Zc=
github.com/anchore/fangs v0.1.1 h1:NBTHocmWM2/0gNhebpoE/wEB0Z0nxh2lESww2o/Uf5M=
github.com/anchore/fangs v0.1.1/go.mod h1:82oZuk4+RynOvAoxnXKmI1zO5xk/kbOw+5t4fAAPSsk=
github.com/anchore/go-collections v0.1.1 h1:kGlmSehs+ctTBZr+98F2+taHeolHy+XDx1Nczl8GZc8=
@@ -150,8 +150,8 @@ github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZV
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
github.com/anchore/packageurl-go v0.2.0 h1:CkrM4RMUwrEGAiE1OVlxaZNzWj0TuHRey7o4T/EAErk=
github.com/anchore/packageurl-go v0.2.0/go.mod h1:2JCgOQMIsqZ7TmliXG4PnUthPJAKE3mWQbsW2XHjAOE=
github.com/anchore/stereoscope v0.3.5-0.20261030123700-09449eab9587 h1:7EEAobOCw3BlbtXJW9ti5hjqu7Z4Mcs7g9NU1Ak/haA=
github.com/anchore/stereoscope v0.3.5-0.20261030123700-09449eab9587/go.mod h1:sfJpowN3ZfLVtx0QTc+3/kdM7ub37Hpi9aBVmdANqz4=
github.com/anchore/stereoscope v0.4.0 h1:MDL7YFRDaGzhCdjm/s+em1D/X9HwnZMYupfgg+mvqPI=
github.com/anchore/stereoscope v0.4.0/go.mod h1:hYJsi3M8a8N1O66u+rMQSgv5TREGM7QIjKBjPPnwiD8=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
@@ -316,8 +316,8 @@ github.com/containerd/platforms v1.0.0-rc.5 h1:vXd569rDrz8LeMXzAnBsy6LADV5YtsD8o
github.com/containerd/platforms v1.0.0-rc.5/go.mod h1:lKlMXyLybmBedS/JJm11uDofzI8L2v0J2ZbYvNsbq1A=
github.com/containerd/plugin v1.1.0 h1:O+7lczNJVMy8rz0YNx3xGB8tTf5qY4i5abF041Ew19U=
github.com/containerd/plugin v1.1.0/go.mod h1:qBTum+A8lJ6lO44A19Eo7y1OlcLj4OWFH1DA/vnHmcc=
github.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw=
github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY=
github.com/containerd/stargz-snapshotter/estargz v0.19.0 h1:tak4qAx648jBAgZmywkd+6kaJ5pqSOVzKYB5DcVSHxk=
github.com/containerd/stargz-snapshotter/estargz v0.19.0/go.mod h1:Cr0pxOkuN7Y61+Sik6X6/nPtePW7hsKWdBt+MoHQRr0=
github.com/containerd/ttrpc v1.2.9 h1:ha0ak962T0s3CA/RoZ6S6xiWZQF24GrBaEpiGX1uihg=
github.com/containerd/ttrpc v1.2.9/go.mod h1:jjtQRwXm4DL3KsHKW8vDiUOV6wO0hi6IPhmJhxU7aEs=
github.com/containerd/typeurl/v2 v2.3.0 h1:HZHPhRWo5XMy3QGQoPrUzbW/2ckwjfweHmOwlkIrPAQ=
@@ -342,8 +342,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da h1:ZOjWpVsFZ06eIhnh4mkaceTiVoktdU67+M7KDHJ268M=
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=
github.com/deitch/magic v1.0.0 h1:Nma1YAj7EB8Mlv4pVhbPpUp0CV1luYj2NOnE2+2xPNE=
github.com/deitch/magic v1.0.0/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
github.com/diskfs/go-diskfs v1.9.4 h1:0j2d7eG4IjyxL6+ChWbDPocdBCF6HQ4HBWU2WDYWVnc=
github.com/diskfs/go-diskfs v1.9.4/go.mod h1:TePJORO83Adh5pb2SqsxAwaP0fofFxKLkxctiS/9OQc=
@@ -351,12 +351,12 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
github.com/docker/cli v29.9.1+incompatible h1:E4YGy7TMkPk7mFsXTVUyjHxVeJdjTDfIS0X4Q0+ioQ0=
github.com/docker/cli v29.9.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v29.9.2+incompatible h1:trup/vUxx5uUo2t+87Cd9AmITR+DvKUe4H2tTtZN8FY=
github.com/docker/cli v29.9.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker-credential-helpers v0.9.8 h1:bIREROb7So6PRlq6KTtdS9MPEjC29OQRkFNlvK2OX8Q=
github.com/docker/docker-credential-helpers v0.9.8/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
github.com/docker/docker-credential-helpers v0.9.10 h1:LCWwv7UmS7fQVmdKDWeMuureOeY5kkbC5kZfkzxkS6k=
github.com/docker/docker-credential-helpers v0.9.10/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
github.com/docker/go-connections v0.8.2 h1:9d9DEokx5W7qlr0shkFXIxEA7+TTD+llwzcykSlxMNc=
github.com/docker/go-connections v0.8.2/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@@ -417,15 +417,15 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/gabriel-vasile/mimetype v1.4.15 h1:05iP/CYtZ/w455R/KZM6rZ5ieAdh99UPtd+d3YzLmaI=
github.com/gabriel-vasile/mimetype v1.4.15/go.mod h1:azpTcoLcDZRNgFou5j+APrqQx9HqVPWa6ijYQIIVswQ=
github.com/gabriel-vasile/mimetype v1.4.16 h1:5izNFuvA37st1dDRAcA7TtmngBmRgiIPDmTtiEvjx1E=
github.com/gabriel-vasile/mimetype v1.4.16/go.mod h1:3oFFwxX8kTklZwzIl2aQEDZT0lKY8xH92ST88bAwba4=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/github/go-spdx/v2 v2.7.1 h1:+siV9wnsncI5pg4otH/sKvqGL8UkcLdPh16TSJYY1V4=
github.com/github/go-spdx/v2 v2.7.1/go.mod h1:Ftc45YYG1WzpzwEPKRVm9Jv8vDqOrN4gWoCkK+bHer0=
github.com/github/go-spdx/v2 v2.8.0 h1:WKCnF2Ee/x+zwSIEeQdm6+be0H6PiCNLQmSZ5CFmxMI=
github.com/github/go-spdx/v2 v2.8.0/go.mod h1:Ftc45YYG1WzpzwEPKRVm9Jv8vDqOrN4gWoCkK+bHer0=
github.com/gkampitakis/ciinfo v0.3.4 h1:5eBSibVuSMbb/H6Elc0IIEFbkzCJi3lm94n0+U7Z0KY=
github.com/gkampitakis/ciinfo v0.3.4/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-snaps v0.5.23 h1:okh5QR48zpUjpWtu65AtqxdCY8huJq+dEDuUzd1PuKg=
github.com/gkampitakis/go-snaps v0.5.23/go.mod h1:uy3lVzCCRRsAwYqSocyw5fY8xRLCYEfqoOJNxr8HonM=
github.com/gkampitakis/go-snaps v0.5.24 h1:oyQ/CQA4s0nkVm6CLlM2GJSU8e4p6KGPZbrSCnTNBzE=
github.com/gkampitakis/go-snaps v0.5.24/go.mod h1:uy3lVzCCRRsAwYqSocyw5fY8xRLCYEfqoOJNxr8HonM=
github.com/glebarez/go-sqlite v1.23.0 h1:FyhIq4jqmgphQAUlY79zPldYGwISEZikaDfhiGWkkaI=
github.com/glebarez/go-sqlite v1.23.0/go.mod h1:IIYrOH3L0rHY3jb4IXOHoWdklNajSGUN2eJcvK8WrnI=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
@@ -553,8 +553,8 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 h1:LMLX+LgTNWpfvCBdFebv6EsYotImrt/Ppc5cXIriCSo=
github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3/go.mod h1:jl5iWTm0/hd5PjEYEOuwAJ57L/CibdZfrqZ5XA5GrCk=
github.com/google/pprof v0.0.0-20261016150608-1facf8f91b50 h1:PlNWJRxu5APSV0pWqfIsZ0qt9OOGHSWfZQ4zvx+WgWs=
github.com/google/pprof v0.0.0-20261016150608-1facf8f91b50/go.mod h1:yUo1AMMpsPIDFGuwDK8nLcf8+vvAd5l2O6JDZ6hpwrM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.10 h1:EMp+aOuXN6l8cE/gjF5Bt+vyZxsUuyCWe9chDWR/+uU=
github.com/google/s2a-go v0.1.10/go.mod h1:pz4tyvwXvJLLbyrkh6FW1eS2zPUXMaTmyNhYtyP2tNw=
@@ -577,8 +577,8 @@ github.com/gookit/color v1.6.3 h1:m6E49x+KftGaspcLtPLMsyci2ARhWIUW0PUV1owMlhs=
github.com/gookit/color v1.6.3/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gpustack/gguf-parser-go v0.26.4 h1:B9CRrQBcIB7I/MJFZvzPZ+e+cbc1xBzQJcmpi9l/mKU=
github.com/gpustack/gguf-parser-go v0.26.4/go.mod h1:y4TwTtDqFWTK+xvprOjRUh+dowgU2TKCX37vRKvGiZ0=
github.com/gpustack/gguf-parser-go v0.27.0 h1:eXFU9pmJEMQHOTL9qI742lXHWSa1CtlMWUU3gFce7nM=
github.com/gpustack/gguf-parser-go v0.27.0/go.mod h1:y4TwTtDqFWTK+xvprOjRUh+dowgU2TKCX37vRKvGiZ0=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.74 h1:mymLUKThnV9wFvogOK8NnsMP9/vlhnjXY98gr2QIGW8=
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.74/go.mod h1:Bh9qYL8ehmDxSg14Tk8oxFCP90XHfs6NxV1D84884xA=
@@ -667,8 +667,8 @@ github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0
github.com/klauspost/compress v1.20.3 h1:zWNoFqq/lSuYQRim3dUXlXeA0IqwuZGicdG5ZTfY5j4=
github.com/klauspost/compress v1.20.3/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/pgzip v1.2.7 h1:02QB3Ttao6zOWDnSsv3bIvjN24bX0eGjWniQ8vuBfkA=
github.com/klauspost/pgzip v1.2.7/go.mod h1:g7E6NrOKHOzah4QwK6Ue1tNCJs8IDiNOfjiXTr85U2E=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -709,10 +709,10 @@ github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsRe
github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 h1:P8UmIzZMYDR+NGImiFvErt6VWfIRPuGM+vyjiEdkmIw=
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.27 h1:Feg/Oou5zI/wnpgDF6omIU0OokC9GxLC/WRknhVlIR0=
github.com/mattn/go-runewidth v0.0.27/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8=
github.com/mattn/go-sqlite3 v1.14.48 h1:7XHIgl0a8HwOaiK4E47ozLkST78rR9+OtNGx27D/TFs=
github.com/mattn/go-sqlite3 v1.14.48/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
github.com/mattn/go-runewidth v0.0.31 h1:1oCV4ReTlosDBc6rYRw5cL8S/4y8iv5oRl4SJ5IBgwo=
github.com/mattn/go-runewidth v0.0.31/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8=
github.com/mattn/go-sqlite3 v1.14.52 h1:wVbm2Qnf4OXkqhBTSPuCRZDRnxfbVrrmiCEroVdog8U=
github.com/mattn/go-sqlite3 v1.14.52/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
@@ -775,8 +775,8 @@ github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIf
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/ncruces/go-strftime v1.1.0 h1:vtPmPWMkb539RGV9WpWT9EwJGvrOCKvMNI4obWL47Hk=
github.com/ncruces/go-strftime v1.1.0/go.mod h1:yVaq7iwCN09vHRrKBrrflXT0M9tTMG2KmZ9Fj7xeG/g=
github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1 h1:kpt9ZfKcm+EDG4s40hMwE//d5SBgDjUOrITReV2u4aA=
github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1/go.mod h1:qgCw4bBKZX8qMgGeEZzGFVT3notl42dBjNqO2jut0M0=
github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE=
@@ -882,8 +882,8 @@ github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rYg=
github.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ=
@@ -899,8 +899,8 @@ github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sigstore/fulcio v1.8.7 h1:d7QJQxukgXarqPCT9uDNeyzt1Bbt/biw58/VfOnwI/o=
github.com/sigstore/fulcio v1.8.7/go.mod h1:7fX+QyigZxRGKTgHvTfOfxwwniCDxK02PVloHy5/vg4=
github.com/sigstore/fulcio v1.8.8 h1:AtVoVQ4R7YaP6RHIH9puHyB398CHS/9WYc6d+gKf5Y0=
github.com/sigstore/fulcio v1.8.8/go.mod h1:RaFomAGGM7VZKAR9ZGqQhcf1Peryc9E1020/kbX8Uto=
github.com/sigstore/protobuf-specs v0.5.2 h1:RSWWUY8QrVTxbYH00jY/jg2e7YnjzrpwP+PeHTMll0E=
github.com/sigstore/protobuf-specs v0.5.2/go.mod h1:DRBzpFuE+LnvQMN10/dU6nBeKwVLGEQ6o2FovN2Rats=
github.com/sigstore/sigstore v1.10.11 h1:fjrwDfR0AWmRONYV/hKGJyqbT0osMtaBz9FTZ6MH9XI=
@@ -994,14 +994,16 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.17 h1:flR0y/x1hgM8EGV1AW3Xll6T413G0glV8UfBwR617V4=
github.com/ulikunitz/xz v0.5.17/go.mod h1:H9Rt/W6/Qj27PGauhQc6nfCDy7vHpzsOThBSaYDoEhw=
github.com/varlink/go v0.4.1-0.20261015173642-c935be0c53f7 h1:pl46d1ZU17758S4EQhns0po6ZPtX+EdHgMPd1uvjia4=
github.com/varlink/go v0.4.1-0.20261015173642-c935be0c53f7/go.mod h1:Cqta0IQ13zfx9ZFugzjWDKUhyMryjOfMKoPrC3TY8fc=
github.com/vbatts/go-mtree v0.7.0 h1:ytmOc3MTRidZiBi9VBCyZ2BHe4fZS47L5v7BVXDWW4E=
github.com/vbatts/go-mtree v0.7.0/go.mod h1:EjdpFC+LZy1TXbRGNa1MKKgjQ+7ew3foMFJK8o4/TdY=
github.com/vbatts/tar-split v0.12.3 h1:Cd46rkGXI3Td4yrVNwU8ripbxFaQbmesqhjBUUYAJSw=
github.com/vbatts/tar-split v0.12.3/go.mod h1:sQOc6OlqGCr7HkGx/IDBeKiTIvqhmj8KffNhEXG4Nq0=
github.com/vbauerster/cupwriter v0.0.4 h1:9sBPe0uXWLZuWQU5lqVbhyFlxX6c09asST/YfatFAys=
github.com/vbauerster/cupwriter v0.0.4/go.mod h1:IFyzS6Xis5dnBH/rdAhrnuzg3c+KkUqEN6yE8lhJlDw=
github.com/vbauerster/mpb/v8 v8.14.0 h1:55SR80dptMfASxIG/oCEkBXgBhxeSu4GrVsjl16oKmA=
github.com/vbauerster/mpb/v8 v8.14.0/go.mod h1:HgpQPKfcWe3kbuGGPmi+jatHreMase5C3Fp5dpdAy0Q=
github.com/vbauerster/cupwriter v0.0.5 h1:pxlPgxPLIebXh8lJPOZmn2TmjPE8+PqJIFkKkr7hI9I=
github.com/vbauerster/cupwriter v0.0.5/go.mod h1:ptJDgOtLtGZp1gLzycD0TFnZztDhrQdsikG6EAA4xYQ=
github.com/vbauerster/mpb/v8 v8.16.2 h1:+UH2Nhn6asKkdX58hSgN+5Jqg/JcFSqCcU+8z0IiYYo=
github.com/vbauerster/mpb/v8 v8.16.2/go.mod h1:PFkxR+jl7Eew9ukpdUcodHBGq9ow74b6cXI7xL0t3mA=
github.com/vifraa/gopom v1.0.0 h1:L9XlKbyvid8PAIK8nr0lihMApJQg/12OBvMA28BcWh0=
github.com/vifraa/gopom v1.0.0/go.mod h1:oPa1dcrGrtlO37WPDBm5SqHAT+wTgF8An1Q71Z6Vv4o=
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIqV3d+DOxazTR9v+zgj8+VYuQBzPgBZvWBHA=
@@ -1070,10 +1072,10 @@ go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwj
go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.podman.io/image/v5 v5.41.2 h1:YnVaFrGLPWSBmipKfNvlOsGcBtk5bUxlPxQ+A6CS/uo=
go.podman.io/image/v5 v5.41.2/go.mod h1:T/bzxEFpdpAzyHabPmcq5K+my3wBsht22sFkFjJSKT4=
go.podman.io/storage v1.64.2 h1:sIBU2vsdGo2gghTF17oxw4G4gojEZkPmt0LKiZWIwqc=
go.podman.io/storage v1.64.2/go.mod h1:ft0DzCRMZs1yn0rszmLYXEEwgd7IIc66JRwSRPUDwwc=
go.podman.io/image/v5 v5.42.0 h1:C//Ix0Thj2LYOQO6++NjU3McLFLQbf4czgUyH98R9gc=
go.podman.io/image/v5 v5.42.0/go.mod h1:mmIgf9EdpF68j8vdX1/OxhOSIknU1PO3G6/ClRkrwm4=
go.podman.io/storage v1.65.0 h1:GgY5VibEw6coVhOGYWuxZ4F7H2AaTfPiwL7E1CJ2dnM=
go.podman.io/storage v1.65.0/go.mod h1:ZDXsVSzdho+p4fDky+iMVCPwRtjS1kSiHcyhBwUB6M0=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
@@ -1606,20 +1608,20 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
modernc.org/cc/v4 v4.29.7 h1:q+NXGJ0bK3b4TXFYQQVr9pYETGnmwFWkrUzJnMya/Tg=
modernc.org/cc/v4 v4.29.7/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
modernc.org/ccgo/v4 v4.36.1 h1:ZNIUZAryN0UgnJwtyxrdEzcFc3yD4Cu4AzjfPXsLsIE=
modernc.org/ccgo/v4 v4.36.1/go.mod h1:rrtGc2QkS239nYb/mQNuBMyjq3/y3ZXWbBjPoV3wqzA=
modernc.org/cc/v4 v4.30.3 h1:aDq8gIX1X7+VFgO/JYYji6pLWL2H4tv3g8WatT3KCys=
modernc.org/cc/v4 v4.30.3/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
modernc.org/ccgo/v4 v4.37.0 h1:BAuJCUtIHIxFIYaFhqXIw5YaoMBlNCUlFovejHfMip4=
modernc.org/ccgo/v4 v4.37.0/go.mod h1:/8627VhwWtAbqUXmPORxFQU5SgLrAx2jl9seLw9GBhY=
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/gc/v3 v3.1.5 h1:21ldfPfRYE31Tb7B3mwAK8gy1AxP4+dKjrOQPfqakoc=
modernc.org/gc/v3 v3.1.5/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/gc/v3 v3.2.0 h1:/Y3LGDMQaoYf55PebP1qsZ5FDGgAZyG1RYKEHeQzh1o=
modernc.org/gc/v3 v3.2.0/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.77.1 h1:Ct8j47QtiZ1Enj2DtFXQtUqrPCAjdCmPjtCuvrYQ0Hs=
modernc.org/libc v1.77.1/go.mod h1:87/pZ4L6nD1zqW4nItuS12YO7hN1igAah34xjnQo/W0=
modernc.org/libc v1.79.0 h1:9Dvvv++bAMSkSuBzuOFAatbTV5OIoq6Y6FohmD3e7q8=
modernc.org/libc v1.79.0/go.mod h1:uT3kR61NsbeKJSLqq83GJwSnZMVLlSjyAz4DfTaBy1M=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.12.1 h1:nFMiWrpStgZczNl6XI9GnIk/rWhYIyHGUaR04pGbp9g=
@@ -1628,8 +1630,8 @@ modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.60.1 h1:/blz53O951KWFOso4QQvEs/Fq6cDBKLtMVrYNSeJVKw=
modernc.org/sqlite v1.60.1/go.mod h1:1dIoEagfDE72QytD5scH1lxARtaUgKgHC/NuApA27r0=
modernc.org/sqlite v1.61.0 h1:sQi63oLQ9uquAUA4CzOisH35Q3pEszkPBuHM0tFL8CY=
modernc.org/sqlite v1.61.0/go.mod h1:f4gr5tbpx2umklaT/QVtbi/50hNdM+4ng+2zMo8KXJ0=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
+2 -1
View File
@@ -3,7 +3,7 @@ package internal
const (
// JSONSchemaVersion is the current schema version output by the JSON encoder
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
JSONSchemaVersion = "16.1.12"
JSONSchemaVersion = "16.1.13"
// Changelog
// 16.1.0 - reformulated the python pdm fields (added "URL" and removed the unused "path" field).
@@ -19,4 +19,5 @@ const (
// 16.1.10 - add SafeTensorsModelInfo metadata type for the safetensors AI model cataloger
// 16.1.11 - add CpanDistribution and CpanUnpackedRelease metadata types for the perl catalogers
// 16.1.12 - add fullPath to file coordinates, naming the nested archive chain a file was found in (blank for files not within an archive)
// 16.1.13 - add executable identifiers (ELF GNU and Go build IDs)
)
+17
View File
@@ -0,0 +1,17 @@
package internal
import "context"
type eagerLayerSquashesKey struct{}
// WithEagerLayerSquashes has the image source provider build every layer's squashed tree while it reads the
// image, instead of the first time each one is used. Set it when the scan will read lower layers (any scope but
// squashed): eager squashing overlaps with fetching and indexing the layers, so those scans finish sooner.
func WithEagerLayerSquashes(ctx context.Context) context.Context {
return context.WithValue(ctx, eagerLayerSquashesKey{}, true)
}
func EagerLayerSquashes(ctx context.Context) bool {
v, _ := ctx.Value(eagerLayerSquashesKey{}).(bool)
return v
}
File diff suppressed because it is too large Load Diff
+26 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "anchore.io/schema/syft/json/16.1.12/document",
"$id": "anchore.io/schema/syft/json/16.1.13/document",
"$ref": "#/$defs/Document",
"$defs": {
"AlpmDbEntry": {
@@ -1468,6 +1468,13 @@
"elfSecurityFeatures": {
"$ref": "#/$defs/ELFSecurityFeatures",
"description": "ELFSecurityFeatures contains ELF-specific security hardening information when Format is ELF."
},
"identifiers": {
"items": {
"$ref": "#/$defs/ExecutableIdentifier"
},
"type": "array",
"description": "Identifiers lists self-declared build identifiers found in the binary (e.g. ELF GNU build IDs or Go build IDs)."
}
},
"type": "object",
@@ -1479,6 +1486,24 @@
],
"description": "Executable contains metadata about binary files and their security features."
},
"ExecutableIdentifier": {
"properties": {
"kind": {
"type": "string",
"description": "Kind identifies the type and source of the identifier."
},
"value": {
"type": "string",
"description": "Value is the identifier in the conventional text form for its Kind (e.g. lowercase hex for an ELF GNU build ID)."
}
},
"type": "object",
"required": [
"kind",
"value"
],
"description": "ExecutableIdentifier is a self-declared build identifier used to correlate a binary with its build or debug information."
},
"File": {
"properties": {
"id": {
+127
View File
@@ -2,11 +2,16 @@ package executable
import (
"debug/elf"
"encoding/binary"
"encoding/hex"
"io"
"regexp"
"strings"
"unicode/utf8"
"github.com/scylladb/go-set/strset"
intFile "github.com/anchore/syft/internal/file"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/unknown"
"github.com/anchore/syft/syft/file"
@@ -35,10 +40,132 @@ func findELFFeatures(data *file.Executable, reader unionreader.UnionReader) erro
data.ELFSecurityFeatures = findELFSecurityFeatures(f)
data.HasEntrypoint = elfHasEntrypoint(f)
data.HasExports = elfHasExports(f)
data.Identifiers = findELFIdentifiers(f)
return err
}
const (
// NT_GNU_BUILD_ID is not defined by debug/elf.
ntGNUBuildID = 3
// ELF_NOTE_GOBUILDID_TAG from cmd/link, the note type the go linker uses for the go build ID.
ntGoBuildID = 4
elfNoteOwnerGNU = "GNU"
elfNoteOwnerGo = "Go"
// bound decoded bytes read from any one identifier note section.
maxELFNoteBytes = 64 * intFile.KB
elfNoteHeaderSize = 12
)
type elfNote struct {
owner string
typ uint32
desc []byte
}
// elfIdentifierNote describes where one kind of identifier lives and how its descriptor becomes a value.
type elfIdentifierNote struct {
section string
owner string
typ uint32
kind file.ExecutableIdentifierKind
// encode returns the value for a descriptor, or "" to skip it.
encode func([]byte) string
}
var elfIdentifierNotes = []elfIdentifierNote{
{section: ".note.gnu.build-id", owner: elfNoteOwnerGNU, typ: ntGNUBuildID, kind: file.ELFGNUBuildID, encode: hex.EncodeToString},
// the go linker always writes this note, while it only writes a GNU build ID when asked (-B) or when linking externally
{section: ".note.go.buildid", owner: elfNoteOwnerGo, typ: ntGoBuildID, kind: file.GoBuildID, encode: goBuildIDValue},
}
func findELFIdentifiers(f *elf.File) []file.ExecutableIdentifier {
var ids []file.ExecutableIdentifier
for _, in := range elfIdentifierNotes {
ids = append(ids, findELFNoteIdentifiers(f, in)...)
}
return ids
}
func findELFNoteIdentifiers(f *elf.File, in elfIdentifierNote) []file.ExecutableIdentifier {
s := f.Section(in.section)
// real identifier notes are SHF_ALLOC, which the gABI forbids compressing, so a compressed one is
// hostile or broken and is never decompressed
if s == nil || s.Type != elf.SHT_NOTE || s.Flags&elf.SHF_COMPRESSED != 0 {
return nil
}
data, err := io.ReadAll(io.LimitReader(s.Open(), maxELFNoteBytes))
if err != nil {
log.WithFields("error", err, "section", in.section).Trace("unable to read ELF identifier note")
return nil
}
var ids []file.ExecutableIdentifier
seen := strset.New()
for _, n := range parseELFNotes(data, s.Addralign, f.ByteOrder) {
if n.owner != in.owner || n.typ != in.typ || len(n.desc) == 0 {
continue
}
value := in.encode(n.desc)
if value == "" || seen.Has(value) {
continue
}
seen.Add(value)
ids = append(ids, file.ExecutableIdentifier{Kind: in.kind, Value: value})
}
return ids
}
// goBuildIDValue keeps the go build ID as the text the go toolchain prints for it (e.g. "go tool buildid").
func goBuildIDValue(desc []byte) string {
if !utf8.Valid(desc) {
return ""
}
return string(desc)
}
// parseELFNotes decodes the Elf_Nhdr records in a note region, stopping at the first truncated record.
func parseELFNotes(data []byte, align uint64, order binary.ByteOrder) []elfNote {
// Some GNU property note regions use 8-byte alignment instead of 4.
if align != 8 {
align = 4
}
var notes []elfNote
for len(data) >= elfNoteHeaderSize {
nameSize := uint64(order.Uint32(data[0:4]))
descSize := uint64(order.Uint32(data[4:8]))
typ := order.Uint32(data[8:12])
nameEnd := elfNoteHeaderSize + nameSize
descStart := alignUp(nameEnd, align)
descEnd := descStart + descSize
if descEnd > uint64(len(data)) {
break
}
notes = append(notes, elfNote{
owner: strings.TrimRight(string(data[elfNoteHeaderSize:nameEnd]), "\x00"),
typ: typ,
desc: data[descStart:descEnd],
})
next := alignUp(descEnd, align)
if next >= uint64(len(data)) {
break
}
data = data[next:]
}
return notes
}
func alignUp(n, align uint64) uint64 {
return (n + align - 1) &^ (align - 1)
}
func findELFSecurityFeatures(f *elf.File) *file.ELFSecurityFeatures {
return &file.ELFSecurityFeatures{
SymbolTableStripped: isElfSymbolTableStripped(f),
+214 -3
View File
@@ -4,8 +4,12 @@ import (
"bytes"
"debug/elf"
"encoding/binary"
"encoding/hex"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
@@ -13,6 +17,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/internal/elfutil"
"github.com/anchore/syft/syft/internal/unionreader"
)
@@ -285,6 +290,12 @@ func Test_hasElfDynTag(t *testing.T) {
// elfWithDynamicSection builds a little-endian ELF holding only a null section and a SHT_DYNAMIC section.
func elfWithDynamicSection(t *testing.T, class elf.Class, dynamic []byte) []byte {
t.Helper()
return elfWithSection(t, class, elf.SHT_DYNAMIC, 1, dynamic)
}
// elfWithSection builds a little-endian ELF holding only a null section and one section of the given type.
func elfWithSection(t *testing.T, class elf.Class, typ elf.SectionType, align uint64, data []byte) []byte {
t.Helper()
ident := [elf.EI_NIDENT]byte{0x7f, 'E', 'L', 'F', byte(class), byte(elf.ELFDATA2LSB), byte(elf.EV_CURRENT)}
var buf bytes.Buffer
@@ -300,7 +311,7 @@ func elfWithDynamicSection(t *testing.T, class elf.Class, dynamic []byte) []byte
Shoff: uint32(ehsize), Ehsize: uint16(ehsize), Shentsize: uint16(shentsize), Shnum: 2,
})
write(elf.Section32{})
write(elf.Section32{Type: uint32(elf.SHT_DYNAMIC), Off: uint32(dataOff), Size: uint32(len(dynamic)), Addralign: 1})
write(elf.Section32{Type: uint32(typ), Off: uint32(dataOff), Size: uint32(len(data)), Addralign: uint32(align)})
} else {
ehsize, shentsize := binary.Size(elf.Header64{}), binary.Size(elf.Section64{})
dataOff := ehsize + 2*shentsize
@@ -309,8 +320,208 @@ func elfWithDynamicSection(t *testing.T, class elf.Class, dynamic []byte) []byte
Shoff: uint64(ehsize), Ehsize: uint16(ehsize), Shentsize: uint16(shentsize), Shnum: 2,
})
write(elf.Section64{})
write(elf.Section64{Type: uint32(elf.SHT_DYNAMIC), Off: uint64(dataOff), Size: uint64(len(dynamic)), Addralign: 1})
write(elf.Section64{Type: uint32(typ), Off: uint64(dataOff), Size: uint64(len(data)), Addralign: align})
}
buf.Write(dynamic)
buf.Write(data)
return buf.Bytes()
}
// encodeELFNote encodes a single little-endian Elf_Nhdr record, padding name and descriptor to align.
func encodeELFNote(owner string, typ uint32, desc []byte, align int) []byte {
pad := func(b []byte) []byte {
for len(b)%align != 0 {
b = append(b, 0)
}
return b
}
name := append([]byte(owner), 0)
out := binary.LittleEndian.AppendUint32(nil, uint32(len(name)))
out = binary.LittleEndian.AppendUint32(out, uint32(len(desc)))
out = binary.LittleEndian.AppendUint32(out, typ)
out = pad(append(out, name...))
return pad(append(out, desc...))
}
func Test_findELFIdentifiers(t *testing.T) {
sha1ID := bytes.Repeat([]byte{0xab}, 20)
customID := []byte{0xde, 0xad, 0xbe, 0xef}
longID := bytes.Repeat([]byte{0x01}, 32)
buildID := func(v []byte) file.ExecutableIdentifier {
return file.ExecutableIdentifier{Kind: file.ELFGNUBuildID, Value: hex.EncodeToString(v)}
}
const ntGNUABITag, ntGNUProperty = 1, 5
tests := []struct {
name string
elf []byte
sectionName string
want []file.ExecutableIdentifier
}{
{
name: "sha1-length build id",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("GNU", ntGNUBuildID, sha1ID, 4)),
sectionName: ".note.gnu.build-id",
want: []file.ExecutableIdentifier{buildID(sha1ID)},
},
{
name: "caller-chosen short build id",
elf: elfWithSection(t, elf.ELFCLASS32, elf.SHT_NOTE, 4, encodeELFNote("GNU", ntGNUBuildID, customID, 4)),
sectionName: ".note.gnu.build-id",
want: []file.ExecutableIdentifier{buildID(customID)},
},
{
name: "build id after other notes in the same section",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, append(
encodeELFNote("GNU", ntGNUABITag, make([]byte, 16), 4),
encodeELFNote("GNU", ntGNUBuildID, longID, 4)...,
)),
sectionName: ".note.gnu.build-id",
want: []file.ExecutableIdentifier{buildID(longID)},
},
{
name: "8-byte aligned note section",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 8, append(
encodeELFNote("GNU", ntGNUProperty, make([]byte, 12), 8),
encodeELFNote("GNU", ntGNUBuildID, customID, 8)...,
)),
sectionName: ".note.gnu.build-id",
want: []file.ExecutableIdentifier{buildID(customID)},
},
{
name: "duplicate build ids",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, bytes.Repeat(
encodeELFNote("GNU", ntGNUBuildID, customID, 4), 2,
)),
sectionName: ".note.gnu.build-id",
want: []file.ExecutableIdentifier{buildID(customID)},
},
{
name: "build id in another section is ignored",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("GNU", ntGNUBuildID, sha1ID, 4)),
sectionName: ".note.other",
},
{
name: "build-id section with another section type is ignored",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_PROGBITS, 4, encodeELFNote("GNU", ntGNUBuildID, sha1ID, 4)),
sectionName: ".note.gnu.build-id",
},
{
name: "build-id section with another owner is ignored",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("FDO", ntGNUBuildID, sha1ID, 4)),
sectionName: ".note.gnu.build-id",
},
{
name: "build-id section with another note type is ignored",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("GNU", ntGNUABITag, sha1ID, 4)),
sectionName: ".note.gnu.build-id",
},
{
name: "empty descriptor is ignored",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("GNU", ntGNUBuildID, nil, 4)),
sectionName: ".note.gnu.build-id",
},
{
name: "truncated descriptor is ignored",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("GNU", ntGNUBuildID, sha1ID, 4)[:20]),
sectionName: ".note.gnu.build-id",
},
{
name: "go build id",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("Go\x00", ntGoBuildID, []byte("action/content"), 4)),
sectionName: ".note.go.buildid",
want: []file.ExecutableIdentifier{{Kind: file.GoBuildID, Value: "action/content"}},
},
{
name: "go build id that is not utf-8 is ignored",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("Go\x00", ntGoBuildID, []byte{0xff, 0xfe}, 4)),
sectionName: ".note.go.buildid",
},
{
name: "gnu build id note in the go section is ignored",
elf: elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("GNU", ntGNUBuildID, sha1ID, 4)),
sectionName: ".note.go.buildid",
},
{
name: "no build-id section",
elf: elfWithDynamicSection(t, elf.ELFCLASS64, nil),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := elfutil.NewFile(bytes.NewReader(tt.elf))
require.NoError(t, err)
f.Sections[1].Name = tt.sectionName
assert.Equal(t, tt.want, findELFIdentifiers(f))
})
}
}
func Test_findELFIdentifiers_compressedSectionIgnored(t *testing.T) {
f, err := elfutil.NewFile(bytes.NewReader(elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, encodeELFNote("GNU", ntGNUBuildID, []byte{0xde, 0xad}, 4))))
require.NoError(t, err)
f.Sections[1].Name = ".note.gnu.build-id"
f.Sections[1].Flags |= elf.SHF_COMPRESSED
assert.Nil(t, findELFIdentifiers(f))
}
type countingNoteReader struct {
io.ReaderAt
bytesRead int
}
func (r *countingNoteReader) ReadAt(p []byte, off int64) (int, error) {
n, err := r.ReaderAt.ReadAt(p, off)
r.bytesRead += n
return n, err
}
func Test_findELFIdentifiers_readLimit(t *testing.T) {
id := encodeELFNote("GNU", ntGNUBuildID, []byte{0xde, 0xad, 0xbe, 0xef}, 4)
data := append(id, make([]byte, maxELFNoteBytes)...)
r := &countingNoteReader{ReaderAt: bytes.NewReader(elfWithSection(t, elf.ELFCLASS64, elf.SHT_NOTE, 4, data))}
f, err := elfutil.NewFile(r)
require.NoError(t, err)
f.Sections[1].Name = ".note.gnu.build-id"
r.bytesRead = 0
assert.Equal(t, []file.ExecutableIdentifier{{Kind: file.ELFGNUBuildID, Value: "deadbeef"}}, findELFIdentifiers(f))
assert.Equal(t, maxELFNoteBytes, r.bytesRead)
}
func Test_parseELFNotes_bigEndian(t *testing.T) {
data := []byte{0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 'G', 'N', 'U', 0, 0xde, 0xad, 0xbe, 0xef}
assert.Equal(t, []elfNote{{owner: "GNU", typ: ntGNUBuildID, desc: data[16:]}}, parseELFNotes(data, 4, binary.BigEndian))
}
// Test_findELFFeatures_realLinkerIdentifiers proves identifiers are picked up from real linker output, not just
// hand-built notes. The go toolchain is the one linker every test environment has, and -B makes it emit a GNU
// build ID next to the go build ID it always writes.
func Test_findELFFeatures_realLinkerIdentifiers(t *testing.T) {
if testing.Short() {
t.Skip("builds a go binary")
}
dir := t.TempDir()
src := filepath.Join(dir, "main.go")
bin := filepath.Join(dir, "main")
require.NoError(t, os.WriteFile(src, []byte("package main\n\nfunc main() {}\n"), 0o600))
build := exec.Command("go", "build", "-trimpath", "-ldflags=-B 0x0123456789abcdef", "-o", bin, src)
build.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=0", "GOFLAGS=", "GOWORK=off")
out, err := build.CombinedOutput()
require.NoError(t, err, string(out))
goBuildID, err := exec.Command("go", "tool", "buildid", bin).Output()
require.NoError(t, err)
f, err := os.Open(bin)
require.NoError(t, err)
t.Cleanup(func() { _ = f.Close() })
var data file.Executable
require.NoError(t, findELFFeatures(&data, f))
assert.Equal(t, []file.ExecutableIdentifier{
{Kind: file.ELFGNUBuildID, Value: "0123456789abcdef"},
{Kind: file.GoBuildID, Value: strings.TrimSpace(string(goBuildID))},
}, data.Identifiers)
}
+19
View File
@@ -6,6 +6,9 @@ type (
// RelocationReadOnly indicates the RELRO security protection level applied to an ELF binary.
RelocationReadOnly string
// ExecutableIdentifierKind identifies the type and source of an executable identifier.
ExecutableIdentifierKind string
)
const (
@@ -16,6 +19,9 @@ const (
RelocationReadOnlyNone RelocationReadOnly = "none" // no RELRO protection
RelocationReadOnlyPartial RelocationReadOnly = "partial" // partial RELRO protection
RelocationReadOnlyFull RelocationReadOnly = "full" // full RELRO protection
ELFGNUBuildID ExecutableIdentifierKind = "elf-gnu-build-id" // GNU build ID from an ELF .note.gnu.build-id note
GoBuildID ExecutableIdentifierKind = "go-build-id" // build ID written by the go linker
)
// Executable contains metadata about binary files and their security features.
@@ -34,6 +40,19 @@ type Executable struct {
// ELFSecurityFeatures contains ELF-specific security hardening information when Format is ELF.
ELFSecurityFeatures *ELFSecurityFeatures `json:"elfSecurityFeatures,omitempty" yaml:"elfSecurityFeatures" mapstructure:"elfSecurityFeatures"`
// Identifiers lists self-declared build identifiers found in the binary (e.g. ELF GNU build IDs or Go build IDs).
Identifiers []ExecutableIdentifier `json:"identifiers,omitempty" yaml:"identifiers" mapstructure:"identifiers"`
}
// ExecutableIdentifier is a self-declared build identifier used to correlate a binary with its build or debug information.
// It can survive stripping; use file digests to verify content.
type ExecutableIdentifier struct {
// Kind identifies the type and source of the identifier.
Kind ExecutableIdentifierKind `json:"kind" yaml:"kind" mapstructure:"kind"`
// Value is the identifier in the conventional text form for its Kind (e.g. lowercase hex for an ELF GNU build ID).
Value string `json:"value" yaml:"value" mapstructure:"value"`
}
// ELFSecurityFeatures captures security hardening and protection mechanisms in ELF binaries.
+10
View File
@@ -219,6 +219,9 @@ func Test_encodeDecodeFileMetadata(t *testing.T) {
Executables: map[file.Coordinates]file.Executable{
c: {
Format: file.ELF,
Identifiers: []file.ExecutableIdentifier{
{Kind: file.ELFGNUBuildID, Value: "0123456789abcdef"},
},
ELFSecurityFeatures: &file.ELFSecurityFeatures{
SymbolTableStripped: false,
StackCanary: boolRef(true),
@@ -288,4 +291,11 @@ func Test_encodeDecodeFileMetadata(t *testing.T) {
assert.Equal(t, internal.JSONSchemaVersion, decodedVersion)
require.Equal(t, s, *got)
executable := s.Artifacts.Executables[c]
executable.Identifiers = nil
s.Artifacts.Executables[c] = executable
buf.Reset()
require.NoError(t, enc.Encode(buf, s))
assert.NotContains(t, buf.String(), `"identifiers"`)
}
+3
View File
@@ -82,6 +82,9 @@ var sectionsReadByName = map[string]struct{}{
".gopclntab": {},
".note.package": {},
".modinfo": {},
// identifier notes read by the executable cataloger
".note.gnu.build-id": {},
".note.go.buildid": {},
}
// wire sizes of the structures we decode, which differ between the two ELF classes
+2 -2
View File
@@ -41,8 +41,8 @@ var (
// inject the correct version into the main module of the build process
knownBuildFlagPatterns = []*regexp.Regexp{
regexp.MustCompile(`(?m)\.[a-zA-Z0-9]*([rR]elease)?([gG]it)?([bB]uild)?[vV]er(sion)?=(\S+/)*(?P<version>v?\d+.\d+.\d+[-\w]*)`),
regexp.MustCompile(`(?m)\.[a-zA-Z0-9]*([tT]ag)=(\S+/)*(?P<version>v?\d+.\d+.\d+[-\w]*)`),
regexp.MustCompile(`(?m)\.[a-zA-Z0-9]*([rR]elease)?([gG]it)?([bB]uild)?[vV]er(sion)?=(\S+/)*(?P<version>v?\d+.\d+.\d+[-\w]*(?:\.[-\w]+)*)`),
regexp.MustCompile(`(?m)\.[a-zA-Z0-9]*([tT]ag)=(\S+/)*(?P<version>v?\d+.\d+.\d+[-\w]*(?:\.[-\w]+)*)`),
}
)
@@ -1285,6 +1285,20 @@ func Test_extractVersionFromLDFlags(t *testing.T) {
wantMajorVersion: "2",
wantFullVersion: "v2.4.5",
},
{
name: "pre-release version with dot-separated identifiers",
mainModule: "github.com/foo/bar",
ldflags: ` build -ldflags="-s -w -X 'github.com/foo/bar/version.gitVersion=v1.28.0-rc.1' -X github.com/foo/bar/version.gitCommit=abc123"`,
wantMajorVersion: "1",
wantFullVersion: "v1.28.0-rc.1",
},
{
name: "pre-release version with multiple dot-separated identifiers",
mainModule: "github.com/foo/bar",
ldflags: ` build -ldflags="-X main.version=2.0.0-beta.2.1"`,
wantMajorVersion: "2",
wantFullVersion: "v2.0.0-beta.2.1",
},
///////////////////////////////////////////////////////////////////
// don't know how to handle these... yet
//{
@@ -141,9 +141,16 @@ func FromDictionaryFind(p pkg.Package) ([]cpe.CPE, bool) {
// generate the minimal set of representative CPEs, which implies that optional fields should not be included
// (such as target SW).
func FromPackageAttributes(p pkg.Package) []cpe.CPE {
switch p.Type {
case pkg.KbPkg:
// Microsoft KB packages are patches, not products: the name is an MSRC product ID and the
// version a KB number, neither of which maps onto a CPE vendor, product or version. They are
// matched against MSRC data by name and version, so a generated CPE is only noise, and one
// that NVD-based matching could misread.
return nil
case pkg.ModelPkg:
// ML models should not have CPEs as they are not traditional software packages
// and don't fit the vulnerability model used for software packages.
if p.Type == pkg.ModelPkg {
return nil
}
@@ -227,6 +234,10 @@ func candidateTargetSw(p pkg.Package) []string {
// NVD records CPAN distributions with perl in target_sw, e.g.
// cpe:2.3:a:mojolicious:mojolicious:*:*:*:*:*:perl:*:*
return []string{"perl"}
case p.Type == pkg.TerraformPkg:
// NVD records terraform providers with the provider type in target_sw, e.g.
// cpe:2.3:a:hashicorp:terraform_provider:*:*:*:*:*:vault:*:*
return candidateTargetSwForTerraformProvider(p)
}
return []string{cpe.Any}
@@ -325,6 +336,9 @@ func candidateVendorsByType(p pkg.Package, vendors fieldCandidateSet) fieldCandi
case pkg.WordpressPluginEntry:
vendors.clear()
vendors.union(candidateVendorsForWordpressPlugin(p))
case pkg.TerraformLockProviderEntry:
vendors.clear()
vendors.union(candidateVendorsForTerraformProvider(p))
}
return vendors
}
@@ -370,6 +384,9 @@ func candidateProductSet(p pkg.Package) fieldCandidateSet {
case pkg.WordpressPluginEntry:
products.clear()
products.union(candidateProductsForWordpressPlugin(p))
case pkg.TerraformLockProviderEntry:
products.clear()
products.union(candidateProductsForTerraformProvider(p))
}
// it is never OK to have candidates with these values ["" and "*"] (since CPEs will match any other value)
@@ -892,6 +892,48 @@ func TestGeneratePackageCPEs(t *testing.T) {
},
expected: []string{},
},
{
name: "Microsoft KB package should generate no CPEs",
p: pkg.Package{
Name: "12437",
Version: "935509",
Type: pkg.KbPkg,
Metadata: pkg.MicrosoftKbPatch{ProductID: "12437", Kb: "935509"},
},
expected: []string{},
},
{
name: "terraform provider generates NVD terraform_provider CPEs not application CPEs",
p: pkg.Package{
Name: "registry.terraform.io/grafana/grafana",
Version: "4.45.2",
Type: pkg.TerraformPkg,
Language: pkg.Go,
Metadata: pkg.TerraformLockProviderEntry{
URL: "registry.terraform.io/grafana/grafana",
Version: "4.45.2",
},
},
expected: []string{
"cpe:2.3:a:grafana:terraform_provider:4.45.2:*:*:*:*:grafana:*:*",
},
},
{
name: "terraform provider with different namespace and type",
p: pkg.Package{
Name: "registry.terraform.io/hashicorp/aws",
Version: "5.72.1",
Type: pkg.TerraformPkg,
Language: pkg.Go,
Metadata: pkg.TerraformLockProviderEntry{
URL: "registry.terraform.io/hashicorp/aws",
Version: "5.72.1",
},
},
expected: []string{
"cpe:2.3:a:hashicorp:terraform_provider:5.72.1:*:*:*:*:aws:*:*",
},
},
{
name: "rust package",
p: pkg.Package{
@@ -0,0 +1,56 @@
package cpegenerate
import (
"strings"
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/pkg"
)
// NVD records terraform providers with a fixed "terraform_provider" product and the provider type in target_sw, e.g.
// cpe:2.3:a:hashicorp:terraform_provider:*:*:*:*:*:vault:*:*
const terraformProviderProduct = "terraform_provider"
func candidateVendorsForTerraformProvider(p pkg.Package) fieldCandidateSet {
vendors := newFieldCandidateSet()
namespace, _ := parseTerraformProviderName(p.Name)
if namespace != "" {
vendors.addValue(namespace)
}
return vendors
}
func candidateProductsForTerraformProvider(p pkg.Package) fieldCandidateSet {
products := newFieldCandidateSet()
_, providerType := parseTerraformProviderName(p.Name)
if providerType != "" {
products.add(fieldCandidate{
value: terraformProviderProduct,
disallowSubSelections: true,
disallowDelimiterVariations: true,
})
}
return products
}
func candidateTargetSwForTerraformProvider(p pkg.Package) []string {
_, providerType := parseTerraformProviderName(p.Name)
if providerType == "" {
return []string{cpe.Any}
}
return []string{providerType}
}
// parseTerraformProviderName extracts the namespace and type from a terraform provider
// source address. The expected format is "registry.terraform.io/<namespace>/<type>".
func parseTerraformProviderName(name string) (namespace, providerType string) {
parts := strings.Split(name, "/")
if len(parts) < 3 {
return "", ""
}
return parts[len(parts)-2], parts[len(parts)-1]
}
@@ -0,0 +1,172 @@
package cpegenerate
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/pkg"
)
func Test_candidateVendorsForTerraformProvider(t *testing.T) {
tests := []struct {
name string
pkg pkg.Package
expected []string
}{
{
name: "hashicorp/aws provider",
pkg: pkg.Package{
Name: "registry.terraform.io/hashicorp/aws",
},
expected: []string{"hashicorp"},
},
{
name: "grafana/grafana provider",
pkg: pkg.Package{
Name: "registry.terraform.io/grafana/grafana",
},
expected: []string{"grafana"},
},
{
name: "hashicorp/google provider",
pkg: pkg.Package{
Name: "registry.terraform.io/hashicorp/google",
},
expected: []string{"hashicorp"},
},
{
name: "malformed name with fewer than 3 segments",
pkg: pkg.Package{
Name: "hashicorp/aws",
},
expected: []string{},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := candidateVendorsForTerraformProvider(test.pkg).uniqueValues()
assert.ElementsMatch(t, test.expected, actual)
})
}
}
func Test_candidateProductsForTerraformProvider(t *testing.T) {
tests := []struct {
name string
pkg pkg.Package
expected []string
}{
{
name: "hashicorp/aws provider",
pkg: pkg.Package{
Name: "registry.terraform.io/hashicorp/aws",
},
expected: []string{"terraform_provider"},
},
{
name: "grafana/grafana provider",
pkg: pkg.Package{
Name: "registry.terraform.io/grafana/grafana",
},
expected: []string{"terraform_provider"},
},
{
name: "hashicorp/google provider",
pkg: pkg.Package{
Name: "registry.terraform.io/hashicorp/google",
},
expected: []string{"terraform_provider"},
},
{
name: "malformed name with fewer than 3 segments",
pkg: pkg.Package{
Name: "hashicorp/aws",
},
expected: []string{},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := candidateProductsForTerraformProvider(test.pkg).uniqueValues()
assert.ElementsMatch(t, test.expected, actual)
})
}
}
func Test_candidateTargetSwForTerraformProvider(t *testing.T) {
tests := []struct {
name string
pkg pkg.Package
expected []string
}{
{
name: "hashicorp/aws provider",
pkg: pkg.Package{
Name: "registry.terraform.io/hashicorp/aws",
},
expected: []string{"aws"},
},
{
name: "grafana/grafana provider",
pkg: pkg.Package{
Name: "registry.terraform.io/grafana/grafana",
},
expected: []string{"grafana"},
},
{
name: "malformed name with fewer than 3 segments",
pkg: pkg.Package{
Name: "hashicorp/aws",
},
expected: []string{cpe.Any},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expected, candidateTargetSwForTerraformProvider(test.pkg))
})
}
}
func Test_parseTerraformProviderName(t *testing.T) {
tests := []struct {
name string
input string
expectedNamespace string
expectedType string
}{
{
name: "standard provider",
input: "registry.terraform.io/hashicorp/aws",
expectedNamespace: "hashicorp",
expectedType: "aws",
},
{
name: "provider where namespace matches type",
input: "registry.terraform.io/grafana/grafana",
expectedNamespace: "grafana",
expectedType: "grafana",
},
{
name: "too few segments",
input: "hashicorp/aws",
expectedNamespace: "",
expectedType: "",
},
{
name: "single segment",
input: "aws",
expectedNamespace: "",
expectedType: "",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
namespace, providerType := parseTerraformProviderName(test.input)
assert.Equal(t, test.expectedNamespace, namespace)
assert.Equal(t, test.expectedType, providerType)
})
}
}
@@ -6,6 +6,7 @@ import (
"github.com/anchore/go-collections"
"github.com/anchore/stereoscope"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/syft/source"
)
@@ -29,6 +30,10 @@ func (l stereoscopeImageSourceProvider) Name() string {
}
func (l stereoscopeImageSourceProvider) Provide(ctx context.Context) (source.Source, error) {
if !internal.EagerLayerSquashes(ctx) {
// lower layer squashes are only built if something reads them, so a squashed scan never pays for them
ctx = image.WithLazyLayerSquashes(ctx)
}
img, err := l.stereoscopeProvider.Provide(ctx)
if err != nil {
return nil, err
@@ -0,0 +1,76 @@
package stereoscopesource
import (
"context"
"path/filepath"
"testing"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/random"
"github.com/google/go-containerregistry/pkg/v1/tarball"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/stereoscope"
"github.com/anchore/stereoscope/pkg/filetree"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/syft/source"
)
func Test_stereoscopeImageSourceProvider_layerSquashes(t *testing.T) {
img, err := random.Image(1024, 3)
require.NoError(t, err)
tag, err := name.NewTag("localhost/layer-squashes:latest")
require.NoError(t, err)
archive := filepath.Join(t.TempDir(), "image.tar")
require.NoError(t, tarball.WriteToFile(archive, tag, img))
provide := func(t *testing.T, ctx context.Context) *stereoscopeImageSource {
providers := Providers(ProviderConfig{
StereoscopeImageProviderConfig: stereoscope.ImageProviderConfig{UserInput: archive},
})
for _, p := range providers {
if p.Value.Name() != image.DockerTarballSource {
continue
}
src, err := p.Value.Provide(ctx)
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, src.Close()) })
return src.(*stereoscopeImageSource)
}
t.Fatalf("no %s provider", image.DockerTarballSource)
return nil
}
lazy := provide(t, context.Background())
eager := provide(t, internal.WithEagerLayerSquashes(context.Background()))
// lower layers are built on first use unless eager was asked for, the top is the image squash either way
require.Len(t, lazy.image.Layers, 3)
for idx := range lazy.image.Layers {
_, isTree := lazy.image.Layers[idx].SquashedTree.(*filetree.FileTree)
assert.Equalf(t, idx == 2, isTree, "lazy layer %d", idx)
assert.IsTypef(t, &filetree.FileTree{}, eager.image.Layers[idx].SquashedTree, "eager layer %d", idx)
}
// every scope sees the same files either way
for _, scope := range []source.Scope{source.SquashedScope, source.AllLayersScope, source.DeepSquashedScope} {
t.Run(string(scope), func(t *testing.T) {
files := func(src *stereoscopeImageSource) []string {
res, err := src.FileResolver(scope)
require.NoError(t, err)
locs, err := res.FilesByGlob("**/*")
require.NoError(t, err)
var out []string
for _, l := range locs {
out = append(out, l.RealPath+"@"+l.FileSystemID)
}
return out
}
want := files(eager)
require.NotEmpty(t, want)
assert.ElementsMatch(t, want, files(lazy))
})
}
}