Compare commits

...
33 Commits
Author SHA1 Message Date
dependabot[bot] 49736e7c4a chore(deps): bump golang.org/x/net from 0.42.0 to 0.43.0 (#4122)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.42.0 to 0.43.0.
- [Commits](https://github.com/golang/net/compare/v0.42.0...v0.43.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.43.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>
2025-08-08 17:51:06 +00:00
dependabot[bot] 7a9e1e06da chore(deps): bump golang.org/x/mod from 0.26.0 to 0.27.0 (#4123)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/mod/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  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>
2025-08-08 13:35:44 -04:00
dependabot[bot] 7b92913a00 chore(deps): bump github/codeql-action from 3.29.7 to 3.29.8 (#4124)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.7 to 3.29.8.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/51f77329afa6477de8c49fc9c7046c15b9a4e79d...76621b61decf072c1cee8dd1ce2d2a82d33c17ed)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.8
  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>
2025-08-08 13:35:35 -04:00
Will MurphyandKeith Zantow 594b309cdf feat: add binary classifier for hashicorp vault (#4121)
* add binary classifier for hashicorp vault

The Go Binary Cataloger isn't able to parse the version out of the
binary shipped in the DockerHub images of hashicorp/vault because the
version of the main module isn't set in the binary. Therefore, add a
binary classifier cataloger for this binary.

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

* chore: add test fixtures, update vault

Signed-off-by: Keith Zantow <kzantow@gmail.com>

* chore: set binary classifier package type based on PURL

Signed-off-by: Keith Zantow <kzantow@gmail.com>

* chore: use github.com/hashicorp/vault as package name

Signed-off-by: Keith Zantow <kzantow@gmail.com>

* chore: update tests

Signed-off-by: Keith Zantow <kzantow@gmail.com>

---------

Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2025-08-08 13:26:15 -04:00
Keith Zantow 8c6a2bcbb6 fix: nondeterministic Java archive cataloging and improve groupID (#4118)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-08-07 10:55:10 -04:00
dependabot[bot] d4d311155f chore(deps): bump docker/login-action from 3.4.0 to 3.5.0 (#4115)
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/74a5d142397b4f367a81961eba4e8cd7edddf772...184bdaa0721073962dff0199f1fb9940f07167d1)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.5.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>
2025-08-07 10:48:53 -04:00
dependabot[bot] 118f564cf3 chore(deps): bump actions/cache from 4.2.3 to 4.2.4 (#4119)
Bumps [actions/cache](https://github.com/actions/cache) from 4.2.3 to 4.2.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/5a3ec84eff668545956fd18022155c47e93e2684...0400d5f644dc74513175e3cd8d07132dd4860809)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 4.2.4
  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>
2025-08-07 10:47:40 -04:00
dependabot[bot] b59c902996 chore(deps): bump actions/cache in /.github/actions/bootstrap (#4120)
Bumps [actions/cache](https://github.com/actions/cache) from 4.2.3 to 4.2.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/5a3ec84eff668545956fd18022155c47e93e2684...0400d5f644dc74513175e3cd8d07132dd4860809)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 4.2.4
  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>
2025-08-07 10:47:25 -04:00
anchore-actions-token-generator[bot]andspiffcs fad9340051 chore(deps): update tools to latest versions (#4111)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-08-04 11:20:26 -04:00
anchore-actions-token-generator[bot]andwagoodman 3820cba0cd chore(deps): update CPE dictionary index (#4112)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-08-04 11:20:09 -04:00
anchore-actions-token-generator[bot]andspiffcs 5af72b6663 chore(deps): update tools to latest versions (#4108)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-31 12:04:54 -04:00
dependabot[bot] 801b21bb37 chore(deps): bump github/codeql-action from 3.29.4 to 3.29.5 (#4096)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.4 to 3.29.5.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/4e828ff8d448a8a6e532957b1811f387a63867e8...51f77329afa6477de8c49fc9c7046c15b9a4e79d)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.5
  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>
2025-07-30 14:29:07 -04:00
anchore-actions-token-generator[bot]andwagoodman 386ef842d9 chore(deps): update anchore dependencies (#4104)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-07-30 17:41:35 +00:00
bd79463e77 chore(deps): update anchore dependencies (#4098)
* chore(deps): update anchore dependencies

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* address reader close operations

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

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-07-30 17:23:07 +00:00
Alex Goodman 8a7302c5cf migrate to get.anchore.io (#4095)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-07-30 10:54:22 -04:00
dependabot[bot] 28ba092375 chore(deps): bump github.com/anchore/stereoscope (#4091)
Bumps [github.com/anchore/stereoscope](https://github.com/anchore/stereoscope) from 0.1.7-0.20250716200927-94c6f92877d4 to 0.1.7.
- [Release notes](https://github.com/anchore/stereoscope/releases)
- [Changelog](https://github.com/anchore/stereoscope/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/stereoscope/commits/v0.1.7)

---
updated-dependencies:
- dependency-name: github.com/anchore/stereoscope
  dependency-version: 0.1.7
  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>
2025-07-30 09:12:55 -04:00
dependabot[bot] fa68af468d chore(deps): bump github.com/docker/docker (#4092)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.2.2+incompatible to 28.3.3+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.2.2...v28.3.3)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.3+incompatible
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-29 16:29:03 -04:00
dependabot[bot] 700a777356 chore(deps): bump modernc.org/sqlite from 1.38.1 to 1.38.2 (#4088)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.38.1 to 1.38.2.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.38.1...v1.38.2)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.38.2
  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>
2025-07-29 10:29:57 -04:00
dependabot[bot] 71aa59a210 chore(deps): bump github.com/gkampitakis/go-snaps from 0.5.13 to 0.5.14 (#4089)
Bumps [github.com/gkampitakis/go-snaps](https://github.com/gkampitakis/go-snaps) from 0.5.13 to 0.5.14.
- [Release notes](https://github.com/gkampitakis/go-snaps/releases)
- [Commits](https://github.com/gkampitakis/go-snaps/compare/v0.5.13...v0.5.14)

---
updated-dependencies:
- dependency-name: github.com/gkampitakis/go-snaps
  dependency-version: 0.5.14
  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>
2025-07-29 10:29:45 -04:00
dependabot[bot] d0d9c6a8e5 chore(deps): bump github.com/bmatcuk/doublestar/v4 from 4.9.0 to 4.9.1 (#4087) 2025-07-28 13:39:36 -04:00
dependabot[bot] 702b4358e9 chore(deps): bump github.com/olekukonko/tablewriter from 1.0.8 to 1.0.9 (#4086) 2025-07-28 13:39:22 -04:00
dependabot[bot] 4a69c00c23 chore(deps): bump github.com/jedib0t/go-pretty/v6 from 6.6.7 to 6.6.8 (#4085) 2025-07-28 13:39:06 -04:00
dependabot[bot] 998742f38e chore(deps): bump modernc.org/sqlite from 1.38.0 to 1.38.1 (#4084) 2025-07-28 17:38:42 +00:00
anchore-actions-token-generator[bot]andspiffcs bb8ea024e1 chore(deps): update tools to latest versions (#4082)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-28 12:01:09 -04:00
anchore-actions-token-generator[bot]andwagoodman 3f28480b3d chore(deps): update CPE dictionary index (#4083)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-07-28 10:51:16 -04:00
anchore-actions-token-generator[bot]andspiffcs 5465bf4227 chore(deps): update tools to latest versions (#4079)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-24 15:18:12 -04:00
dependabot[bot] 8b2c4a134e chore(deps): bump github/codeql-action from 3.29.3 to 3.29.4 (#4080)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.3 to 3.29.4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/d6bbdef45e766d081b84a2def353b0055f728d3e...4e828ff8d448a8a6e532957b1811f387a63867e8)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.4
  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>
2025-07-24 15:17:49 -04:00
anchore-actions-token-generator[bot] d7046099e9 chore(deps): update tools to latest versions (#4076) 2025-07-23 21:03:20 -04:00
Alex Goodman f0a990b85f chore: add source completion tester (#4077)
* add source completion tester

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

* add missing t.Helper calls

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

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-07-23 13:49:47 +00:00
Keith Zantow 48bf81cf7f fix: align binary java detection with jvm cataloger + support IBM (#4046)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-07-22 12:06:32 -04:00
anchore-actions-token-generator[bot]andspiffcs 78c7cd2cc2 chore(deps): update tools to latest versions (#4072)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-22 09:49:58 -04:00
dependabot[bot] a192787d44 chore(deps): bump github/codeql-action from 3.29.2 to 3.29.3 (#4074)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.2 to 3.29.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/181d5eefc20863364f96762470ba6f862bdef56b...d6bbdef45e766d081b84a2def353b0055f728d3e)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.3
  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>
2025-07-22 09:49:43 -04:00
dependabot[bot] d5a562c368 chore(deps): bump anchore/sbom-action from 0.20.2 to 0.20.4 (#4073)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.20.2 to 0.20.4.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/cee1b8e05ae5b2593a75e197229729eabaa9f8ec...7b36ad622f042cab6f59a75c2ac24ccb256e9b45)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.4
  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>
2025-07-22 09:49:40 -04:00
50 changed files with 1018 additions and 348 deletions
+5 -5
View File
@@ -26,7 +26,7 @@ tools:
# used for linting
- name: golangci-lint
version:
want: v2.2.2
want: v2.3.1
method: github-release
with:
repo: golangci/golangci-lint
@@ -58,7 +58,7 @@ tools:
# used to release all artifacts
- name: goreleaser
version:
want: v2.11.0
want: v2.11.2
method: github-release
with:
repo: goreleaser/goreleaser
@@ -90,7 +90,7 @@ tools:
# used for running all local and CI tasks
- name: task
version:
want: v3.44.0
want: v3.44.1
method: github-release
with:
repo: go-task/task
@@ -98,7 +98,7 @@ tools:
# used for triggering a release
- name: gh
version:
want: v2.76.0
want: v2.76.2
method: github-release
with:
repo: cli/cli
@@ -114,7 +114,7 @@ tools:
# used to upload test fixture cache
- name: yq
version:
want: v4.46.1
want: v4.47.1
method: github-release
with:
repo: mikefarah/yq
+2 -2
View File
@@ -37,7 +37,7 @@ runs:
- name: Restore tool cache
if: inputs.tools == 'true'
id: tool-cache
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ${{ github.workspace }}/.tool
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('.binny.yaml') }}
@@ -63,7 +63,7 @@ runs:
- name: Restore ORAS cache from github actions
if: inputs.download-test-fixture-cache == 'true'
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ${{ github.workspace }}/.tmp/oras-cache
key: ${{ inputs.cache-key-prefix }}-oras-cache
-22
View File
@@ -1,22 +0,0 @@
#!/usr/bin/env bash
set -ue
BIN="syft"
VERSION_FILE="VERSION"
VERSION=$1
# the source of truth as to whether we want to notify users of an update is if the release just created is NOT
# flagged as a pre-release on github
if [[ "$(curl -SsL https://api.github.com/repos/anchore/${BIN}/releases/tags/${VERSION} | jq .prerelease)" == "true" ]] ; then
echo "skipping publishing a version file (this is a pre-release: ${VERSION})"
exit 0
fi
echo "creating and publishing version file (${VERSION})"
# create a version file for version-update checks
echo "${VERSION}" | tee "${VERSION_FILE}"
# upload the version file that supports the application version update check
export AWS_DEFAULT_REGION=us-west-2
aws s3 cp "${VERSION_FILE}" s3://toolbox-data.anchore.io/${BIN}/releases/latest/VERSION
+3 -3
View File
@@ -47,7 +47,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b #v3.29.2
uses: github/codeql-action/init@76621b61decf072c1cee8dd1ce2d2a82d33c17ed #v3.29.5
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -58,7 +58,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@181d5eefc20863364f96762470ba6f862bdef56b #v3.29.2
uses: github/codeql-action/autobuild@76621b61decf072c1cee8dd1ce2d2a82d33c17ed #v3.29.5
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -72,4 +72,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b #v3.29.2
uses: github/codeql-action/analyze@76621b61decf072c1cee8dd1ce2d2a82d33c17ed #v3.29.5
@@ -1,40 +0,0 @@
name: "Release: version file"
on:
workflow_dispatch:
inputs:
version:
description: release version to update the version file with (prefixed with v)
required: true
workflow_call:
inputs:
version:
type: string
description: release version to update the version file with (prefixed with v)
required: true
secrets:
TOOLBOX_AWS_ACCESS_KEY_ID:
required: true
TOOLBOX_AWS_SECRET_ACCESS_KEY:
required: true
jobs:
release:
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Update version file
run: make ci-release-version-file
env:
RELEASE_VERSION: ${{ github.event.inputs.version }}
# for updating the VERSION file in S3...
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
+14 -8
View File
@@ -125,13 +125,13 @@ jobs:
uses: ./.github/actions/bootstrap
- name: Login to Docker Hub
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 #v3.4.0
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 #v3.5.0
with:
username: ${{ secrets.ANCHOREOSSWRITE_DH_USERNAME }}
password: ${{ secrets.ANCHOREOSSWRITE_DH_PAT }}
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 #v3.4.0
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 #v3.5.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -161,7 +161,7 @@ jobs:
# for updating brew formula in anchore/homebrew-syft
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
- uses: anchore/sbom-action@cee1b8e05ae5b2593a75e197229729eabaa9f8ec #v0.20.2
- uses: anchore/sbom-action@7b36ad622f042cab6f59a75c2ac24ccb256e9b45 #v0.20.4
continue-on-error: true
with:
file: go.mod
@@ -177,11 +177,17 @@ jobs:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
if: ${{ success() }}
release-version-file:
release-install-script:
needs: [release]
uses: ./.github/workflows/release-version-file.yaml
if: ${{ needs.release.result == 'success' }}
uses: "anchore/workflows/.github/workflows/release-install-script.yaml@main"
with:
version: ${{ github.event.inputs.version }}
tag: ${{ github.event.inputs.version }}
secrets:
TOOLBOX_AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
TOOLBOX_AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
# needed for r2...
R2_INSTALL_ACCESS_KEY_ID: ${{ secrets.OSS_R2_INSTALL_ACCESS_KEY_ID }}
R2_INSTALL_SECRET_ACCESS_KEY: ${{ secrets.OSS_R2_INSTALL_SECRET_ACCESS_KEY }}
R2_ENDPOINT: ${{ secrets.TOOLBOX_CLOUDFLARE_R2_ENDPOINT }}
# needed for s3...
S3_INSTALL_AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
S3_INSTALL_AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
+5 -5
View File
@@ -90,7 +90,7 @@ jobs:
# why not use actions/upload-artifact? It is very slow (3 minutes to upload ~600MB of data, vs 10 seconds with this approach).
# see https://github.com/actions/upload-artifact/issues/199 for more info
- name: Upload snapshot artifacts
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
# we need to preserve the snapshot data itself as well as the task data that confirms if the
# snapshot build is stale or not. Otherwise the downstream jobs will attempt to rebuild the snapshot
@@ -118,7 +118,7 @@ jobs:
- name: Download snapshot build
id: snapshot-cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
path: |
snapshot
@@ -175,7 +175,7 @@ jobs:
- name: Download snapshot build
id: snapshot-cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
path: |
snapshot
@@ -225,7 +225,7 @@ jobs:
- name: Download snapshot build
id: snapshot-cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
path: |
snapshot
@@ -262,7 +262,7 @@ jobs:
- name: Download snapshot build
id: snapshot-cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
path: |
snapshot
+1 -1
View File
@@ -12,7 +12,7 @@ TASK = $(TOOL_DIR)/task
# note: we need to assume that binny and task have not already been installed
$(BINNY):
@mkdir -p $(TOOL_DIR)
@curl -sSfL https://raw.githubusercontent.com/$(OWNER)/binny/main/install.sh | sh -s -- -b $(TOOL_DIR)
@curl -sSfL https://get.anchore.io/binny | sh -s -- -b $(TOOL_DIR)
# note: we need to assume that binny and task have not already been installed
.PHONY: task
+1 -1
View File
@@ -38,7 +38,7 @@ Syft binaries are provided for Linux, macOS and Windows.
### Recommended
> ```bash
> curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
> curl -sSfL https://get.anchore.io/syft | sudo sh -s -- -b /usr/local/bin
> ```
Install script options:
+1 -11
View File
@@ -91,7 +91,7 @@ tasks:
- "{{ .TOOL_DIR }}/binny"
status:
- "test -f {{ .TOOL_DIR }}/binny"
cmd: "curl -sSfL https://raw.githubusercontent.com/anchore/binny/main/install.sh | sh -s -- -b .tool"
cmd: "curl -sSfL https://get.anchore.io/binny | sh -s -- -b .tool"
silent: true
tools:
@@ -604,16 +604,6 @@ tasks:
silent: true
- "{{ .RELEASE_CMD }}"
ci-release-version-file:
# desc: "[CI only] Update the version file"
deps: [tools]
cmds:
- task: ci-check
- ".github/scripts/update-version-file.sh {{ .RELEASE_VERSION }}"
requires:
vars:
- RELEASE_VERSION
## Cleanup targets #################################
+19 -19
View File
@@ -24,12 +24,12 @@ require (
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115
github.com/anchore/stereoscope v0.1.7-0.20250716200927-94c6f92877d4
github.com/anchore/stereoscope v0.1.8
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
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/bmatcuk/doublestar/v4 v4.9.0
github.com/bmatcuk/doublestar/v4 v4.9.1
github.com/charmbracelet/bubbles v0.21.0
github.com/charmbracelet/bubbletea v1.3.6
github.com/charmbracelet/lipgloss v1.1.0
@@ -41,7 +41,7 @@ require (
github.com/elliotchance/phpserialize v1.4.0
github.com/facebookincubator/nvdtools v0.1.5
github.com/github/go-spdx/v2 v2.3.3
github.com/gkampitakis/go-snaps v0.5.13
github.com/gkampitakis/go-snaps v0.5.14
github.com/go-git/go-billy/v5 v5.6.2
github.com/go-git/go-git/v5 v5.16.2
github.com/go-test/deep v1.1.1
@@ -58,14 +58,14 @@ require (
github.com/hashicorp/hcl/v2 v2.24.0
github.com/iancoleman/strcase v0.3.0
github.com/invopop/jsonschema v0.7.0
github.com/jedib0t/go-pretty/v6 v6.6.7
github.com/jedib0t/go-pretty/v6 v6.6.8
github.com/jinzhu/copier v0.4.0
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
github.com/magiconair/properties v1.8.10
github.com/mholt/archives v0.1.3
github.com/moby/sys/mountinfo v0.7.2
github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1
github.com/olekukonko/tablewriter v1.0.8
github.com/olekukonko/tablewriter v1.0.9
github.com/opencontainers/go-digest v1.0.0
github.com/pelletier/go-toml v1.9.5
github.com/quasilyte/go-ruleguard/dsl v0.3.22
@@ -88,11 +88,11 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0
github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1
go.uber.org/goleak v1.3.0
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
golang.org/x/mod v0.26.0
golang.org/x/net v0.42.0
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
golang.org/x/mod v0.27.0
golang.org/x/net v0.43.0
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.38.0
modernc.org/sqlite v1.38.2
)
require (
@@ -145,9 +145,9 @@ require (
github.com/containerd/typeurl/v2 v2.2.0 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/cli v28.3.0+incompatible // indirect
github.com/docker/cli v28.3.2+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v28.2.2+incompatible // indirect
github.com/docker/docker v28.3.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
@@ -215,8 +215,8 @@ require (
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/nwaples/rardecode/v2 v2.1.0 // indirect
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6 // indirect
github.com/olekukonko/ll v0.0.8 // indirect
github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.0.9 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runtime-spec v1.1.0 // indirect
github.com/opencontainers/selinux v1.11.0 // indirect
@@ -268,14 +268,14 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/crypto v0.41.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/term v0.33.0 // indirect
golang.org/x/text v0.27.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/term v0.34.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.34.0 // indirect
golang.org/x/tools v0.35.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/api v0.203.0 // indirect
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
@@ -284,7 +284,7 @@ require (
google.golang.org/grpc v1.67.3 // indirect
google.golang.org/protobuf v1.36.4 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
modernc.org/libc v1.65.10 // indirect
modernc.org/libc v1.66.3 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)
+44 -42
View File
@@ -694,8 +694,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.1.1-0.20250220190351-d62adb6e1115 h1:ZyRCmiEjnoGJZ1+Ah0ZZ/mKKqNhGcUZBl0s7PTTDzvY=
github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI=
github.com/anchore/stereoscope v0.1.7-0.20250716200927-94c6f92877d4 h1:5UGwBBUAK8i06gDA5JD74vT3qcz4lR7BfLXudpD5y8w=
github.com/anchore/stereoscope v0.1.7-0.20250716200927-94c6f92877d4/go.mod h1:ejAlYkAb/cRvSMlxQlrG2dMruqQpcJAh4w2Fu02FEYQ=
github.com/anchore/stereoscope v0.1.8 h1:K1NRFUqGy6z/jp4ADHNXZWbZ+xd6fPr0Kn4gYp1zm1c=
github.com/anchore/stereoscope v0.1.8/go.mod h1:VA9zyFcUzN7GIFsXfe8lj3Z6Ocs4CP5QZqbmFc1I7ag=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 h1:8PmGpDEZl9yDpcdEr6Odf23feCxK3LNUNMxjXg41pZQ=
@@ -739,8 +739,8 @@ github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef h1:TSFnfbbu2oAO
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo=
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/bmatcuk/doublestar/v4 v4.9.0 h1:DBvuZxjdKkRP/dr4GVV4w2fnmrk5Hxc90T51LZjv0JA=
github.com/bmatcuk/doublestar/v4 v4.9.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A=
@@ -857,12 +857,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 v28.3.0+incompatible h1:s+ttruVLhB5ayeuf2BciwDVxYdKi+RoUlxmwNHV3Vfo=
github.com/docker/cli v28.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v28.3.2+incompatible h1:mOt9fcLE7zaACbxW1GeS65RI67wIJrTnqS3hP2huFsY=
github.com/docker/cli v28.3.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 v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
@@ -936,8 +936,8 @@ github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BN
github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
github.com/gkampitakis/go-snaps v0.5.13 h1:Hhjmvv1WboSCxkR9iU2mj5PQ8tsz/y8ECGrIbjjPF8Q=
github.com/gkampitakis/go-snaps v0.5.13/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
github.com/gkampitakis/go-snaps v0.5.14 h1:3fAqdB6BCPKHDMHAKRwtPUwYexKtGrNuw8HX/T/4neo=
github.com/gkampitakis/go-snaps v0.5.14/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
github.com/glebarez/go-sqlite v1.20.3 h1:89BkqGOXR9oRmG58ZrzgoY/Fhy5x0M+/WV48U5zVrZ4=
github.com/glebarez/go-sqlite v1.20.3/go.mod h1:u3N6D/wftiAzIOJtZl6BmedqxmmkDfH3q+ihjqxC9u0=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
@@ -1187,8 +1187,8 @@ github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy77
github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo=
github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
github.com/jedib0t/go-pretty/v6 v6.6.8 h1:JnnzQeRz2bACBobIaa/r+nqjvws4yEhcmaZ4n1QzsEc=
github.com/jedib0t/go-pretty/v6 v6.6.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
@@ -1346,12 +1346,12 @@ github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9l
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/nwaples/rardecode/v2 v2.1.0 h1:JQl9ZoBPDy+nIZGb1mx8+anfHp/LV3NE2MjMiv0ct/U=
github.com/nwaples/rardecode/v2 v2.1.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6 h1:r3FaAI0NZK3hSmtTDrBVREhKULp8oUeqLT5Eyl2mSPo=
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.0.8 h1:sbGZ1Fx4QxJXEqL/6IG8GEFnYojUSQ45dJVwN2FH2fc=
github.com/olekukonko/ll v0.0.8/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
github.com/olekukonko/tablewriter v1.0.8 h1:f6wJzHg4QUtJdvrVPKco4QTrAylgaU0+b9br/lJxEiQ=
github.com/olekukonko/tablewriter v1.0.8/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs=
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8=
github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -1643,8 +1643,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1660,8 +1660,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -1707,8 +1707,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1777,8 +1777,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1936,8 +1936,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1952,8 +1952,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1974,8 +1974,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -2050,8 +2050,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2382,8 +2382,8 @@ lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
@@ -2393,10 +2393,12 @@ modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJD
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/fileutil v1.3.3 h1:3qaU+7f7xxTUmvU1pJTZiDLAIoJVdUSSauJNHg9yXoA=
modernc.org/fileutil v1.3.3/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM=
modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
@@ -2405,8 +2407,8 @@ modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0=
modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s=
modernc.org/libc v1.65.10 h1:ZwEk8+jhW7qBjHIT+wd0d9VjitRyQef9BnzlzGwMODc=
modernc.org/libc v1.65.10/go.mod h1:StFvYpx7i/mXtBAfVOjaU0PWZOvIRoZSgXhrwXzr8Po=
modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ=
modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
@@ -2424,8 +2426,8 @@ modernc.org/opt v0.1.4/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.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
modernc.org/sqlite v1.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI=
modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE=
modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek=
modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
+7 -2
View File
@@ -6,7 +6,8 @@ PROJECT_NAME=syft
OWNER=anchore
REPO="${PROJECT_NAME}"
GITHUB_DOWNLOAD_PREFIX=https://github.com/${OWNER}/${REPO}/releases/download
INSTALL_SH_BASE_URL=https://raw.githubusercontent.com/${OWNER}/${PROJECT_NAME}
INSTALL_SH_BASE_URL=https://get.anchore.io/${PROJECT_NAME}
LEGACY_INSTALL_SH_BASE_URL=https://raw.githubusercontent.com/${OWNER}/${PROJECT_NAME}
PROGRAM_ARGS=$@
# signature verification options
@@ -836,7 +837,11 @@ EOF
if [ "${DOWNLOAD_TAG_INSTALL_SCRIPT}" = "true" ]; then
export DOWNLOAD_TAG_INSTALL_SCRIPT=false
log_info "fetching release script for tag='${tag}'"
http_copy "${INSTALL_SH_BASE_URL}/${tag}/install.sh" "" | sh -s -- ${PROGRAM_ARGS}
if ! install_script=$(http_copy "${INSTALL_SH_BASE_URL}/${tag}/install.sh" ""); then
log_warn "failed to fetch from ${INSTALL_SH_BASE_URL}, trying fallback URL"
install_script=$(http_copy "${LEGACY_INSTALL_SH_BASE_URL}/${tag}/install.sh" "")
fi
echo "${install_script}" | sh -s -- ${PROGRAM_ARGS}
exit $?
fi
+2 -2
View File
@@ -41,11 +41,11 @@ func MatchNamedCaptureGroups(regEx *regexp.Regexp, content string) map[string]st
// 1.5x the reader chunk size (1MB * 1.5).
func MatchNamedCaptureGroupsFromReader(re *regexp.Regexp, r io.Reader) (map[string]string, error) {
results := make(map[string]string)
_, err := processReaderInChunks(r, readerChunkSize, matchNamedCaptureGroupsHandler(re, results))
matches, err := processReaderInChunks(r, readerChunkSize, matchNamedCaptureGroupsHandler(re, results))
if err != nil {
return nil, err
}
if len(results) == 0 {
if !matches {
return nil, nil
}
return results, nil
@@ -12,6 +12,7 @@ type CompletionTester struct {
}
func NewCompletionTester(t testing.TB, ignore ...any) *CompletionTester {
t.Helper()
tester := &CompletionTester{
valid: AllTypes(),
ignore: ignore,
@@ -23,6 +24,14 @@ func NewCompletionTester(t testing.TB, ignore ...any) *CompletionTester {
return tester
}
func (tr *CompletionTester) Ignore(is ...any) {
tr.ignore = append(tr.ignore, keepNonNil(is...)...)
}
func (tr *CompletionTester) Expect(is ...any) {
tr.valid = append(tr.valid, keepNonNil(is...)...)
}
func (tr *CompletionTester) Tested(t testing.TB, m any) {
t.Helper()
@@ -33,6 +42,13 @@ func (tr *CompletionTester) Tested(t testing.TB, m any) {
t.Fatal("no valid metadata types to test against")
}
ty := reflect.TypeOf(m)
for _, v := range tr.ignore {
if reflect.TypeOf(v) == ty {
return
}
}
for _, v := range tr.valid {
if reflect.TypeOf(v) == ty {
tr.saw = append(tr.saw, m)
@@ -67,3 +83,13 @@ validations:
}
}
}
func keepNonNil(is ...any) []any {
var result []any
for _, i := range is {
if i != nil {
result = append(result, i)
}
}
return result
}
@@ -12,6 +12,7 @@ type CompletionTester struct {
}
func NewCompletionTester(t testing.TB, ignore ...any) *CompletionTester {
t.Helper()
tester := &CompletionTester{
valid: AllTypes(),
ignore: ignore,
@@ -23,6 +24,14 @@ func NewCompletionTester(t testing.TB, ignore ...any) *CompletionTester {
return tester
}
func (tr *CompletionTester) Ignore(is ...any) {
tr.ignore = append(tr.ignore, keepNonNil(is...)...)
}
func (tr *CompletionTester) Expect(is ...any) {
tr.valid = append(tr.valid, keepNonNil(is...)...)
}
func (tr *CompletionTester) Tested(t testing.TB, m any) {
t.Helper()
@@ -33,6 +42,13 @@ func (tr *CompletionTester) Tested(t testing.TB, m any) {
t.Fatal("no valid metadata types to test against")
}
ty := reflect.TypeOf(m)
for _, v := range tr.ignore {
if reflect.TypeOf(v) == ty {
return
}
}
for _, v := range tr.valid {
if reflect.TypeOf(v) == ty {
tr.saw = append(tr.saw, m)
@@ -67,3 +83,13 @@ validations:
}
}
}
func keepNonNil(is ...any) []any {
var result []any
for _, i := range is {
if i != nil {
result = append(result, i)
}
}
return result
}
@@ -75,6 +75,12 @@ func (c cataloger) Catalog(_ context.Context, resolver file.Resolver) ([]pkg.Pac
newPackages:
for i := range newPkgs {
newPkg := &newPkgs[i]
purlType := pkg.TypeFromPURL(newPkg.PURL)
// for certain results, such as hashicorp vault we are returning a golang PURL, so we can use Golang package type,
// despite not having the known metadata, this should result in downstream grype matching to use the golang matcher
if purlType != pkg.UnknownPkg {
newPkg.Type = purlType
}
for j := range packages {
p := &packages[j]
// consolidate identical packages found in different locations or by different classifiers
@@ -92,6 +98,9 @@ func (c cataloger) Catalog(_ context.Context, resolver file.Resolver) ([]pkg.Pac
// mergePackages merges information from the extra package into the target package
func mergePackages(target *pkg.Package, extra *pkg.Package) {
if extra.Type != pkg.BinaryPkg && target.Type == pkg.BinaryPkg {
target.Type = extra.Type
}
// add the locations
target.Locations.Add(extra.Locations.ToSlice()...)
// update the metadata to indicate which classifiers were used
@@ -697,21 +697,21 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
{
logicalFixture: "java-jre-openjdk/1.8.0_352-b08/linux-amd64",
expected: pkg.Package{
Name: "java/jre",
Name: "openjdk",
Version: "1.8.0_352-b08",
Type: "binary",
PURL: "pkg:generic/java/jre@1.8.0_352-b08",
PURL: "pkg:generic/oracle/openjdk@1.8.0_352-b08",
Locations: locations("java"),
Metadata: metadata("java-binary-openjdk", "java"),
Metadata: metadata("java-binary-openjdk-with-update", "java"),
},
},
{
logicalFixture: "java-jre-openjdk/11.0.17/linux-amd64",
expected: pkg.Package{
Name: "java/jre",
Name: "openjdk",
Version: "11.0.17+8-LTS",
Type: "binary",
PURL: "pkg:generic/java/jre@11.0.17%2B8-LTS",
PURL: "pkg:generic/oracle/openjdk@11.0.17%2B8-LTS",
Locations: locations("java"),
Metadata: metadata("java-binary-openjdk", "java"),
},
@@ -719,10 +719,10 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
{
logicalFixture: "java-jre-openjdk-eclipse/11.0.22/linux-amd64",
expected: pkg.Package{
Name: "java/jre",
Name: "openjdk",
Version: "11.0.22+7",
Type: "binary",
PURL: "pkg:generic/java/jre@11.0.22%2B7",
PURL: "pkg:generic/oracle/openjdk@11.0.22%2B7",
Locations: locations("java"),
Metadata: metadata("java-binary-openjdk", "java"),
},
@@ -730,10 +730,10 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
{
logicalFixture: "java-jre-openjdk-arm64-eclipse/11.0.22/linux-arm64",
expected: pkg.Package{
Name: "java/jre",
Name: "openjdk",
Version: "11.0.22+7",
Type: "binary",
PURL: "pkg:generic/java/jre@11.0.22%2B7",
PURL: "pkg:generic/oracle/openjdk@11.0.22%2B7",
Locations: locations("java"),
Metadata: metadata("java-binary-openjdk", "java"),
},
@@ -741,10 +741,10 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
{
logicalFixture: "java-graal-openjdk/17.0.3+7-jvmci-22.1-b06/linux-amd64",
expected: pkg.Package{
Name: "java/graalvm",
Name: "graalvm",
Version: "17.0.3+7-jvmci-22.1-b06",
Type: "binary",
PURL: "pkg:generic/java/graalvm@17.0.3%2B7-jvmci-22.1-b06",
PURL: "pkg:generic/oracle/graalvm@17.0.3%2B7-jvmci-22.1-b06",
Locations: locations("java"),
Metadata: metadata("java-binary-graalvm", "java"),
},
@@ -754,10 +754,10 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
// note: cannot find the original binary, using a custom snippet based on the original snippet in the repo
logicalFixture: "java-jre-oracle/19.0.1/linux-amd64",
expected: pkg.Package{
Name: "java/jre",
Name: "jre",
Version: "19.0.1+10-21",
Type: "binary",
PURL: "pkg:generic/java/jre@19.0.1%2B10-21",
PURL: "pkg:generic/oracle/jre@19.0.1%2B10-21",
Locations: locations("java"),
Metadata: metadata("java-binary-oracle", "java"),
},
@@ -767,10 +767,10 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
// note: cannot find the original binary, using a custom snippet based on the original snippet in the repo
logicalFixture: "java-jre-oracle/19.0.1/darwin",
expected: pkg.Package{
Name: "java/jre",
Name: "jre",
Version: "19.0.1+10-21",
Type: "binary",
PURL: "pkg:generic/java/jre@19.0.1%2B10-21",
PURL: "pkg:generic/oracle/jre@19.0.1%2B10-21",
Locations: locations("java"),
Metadata: metadata("java-binary-oracle", "java"),
},
@@ -778,23 +778,45 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
{
logicalFixture: "java-jre-ibm/1.8.0_391/linux-amd64",
expected: pkg.Package{
Name: "java/jre",
Name: "java",
Version: "1.8.0-foreman_2023_10_12_13_27-b00",
Type: "binary",
PURL: "pkg:generic/java/jre@1.8.0-foreman_2023_10_12_13_27-b00",
PURL: "pkg:generic/ibm/java@1.8.0-foreman_2023_10_12_13_27-b00",
Locations: locations("java"),
Metadata: metadata("java-binary-ibm", "java"),
},
},
{
logicalFixture: "java-ibm-8-jre/1.8.0_451/linux-amd64",
expected: pkg.Package{
Name: "java",
Version: "1.8.0-_2025_04_14_02_37-b00",
Type: "binary",
PURL: "pkg:generic/ibm/java@1.8.0-_2025_04_14_02_37-b00",
Locations: locations("java"),
Metadata: metadata("java-binary-ibm", "java"),
},
},
{
logicalFixture: "java-ibm-8-sdk-alpine/1.8.0_321/linux-amd64",
expected: pkg.Package{
Name: "java_sdk",
Version: "1.8.0-foreman_2022_01_20_09_33-b00",
Type: "binary",
PURL: "pkg:generic/ibm/java_sdk@1.8.0-foreman_2022_01_20_09_33-b00",
Locations: locations("jdb"),
Metadata: metadata("java-sdk-binary-ibm", "jdb"),
},
},
{
logicalFixture: "java-jdk-openjdk/21.0.2+13-LTS/linux-amd64",
expected: pkg.Package{
Name: "java/jdk",
Name: "openjdk",
Version: "21.0.2+13-LTS",
Type: "binary",
PURL: "pkg:generic/java/jdk@21.0.2%2B13-LTS",
PURL: "pkg:generic/oracle/openjdk@21.0.2%2B13-LTS",
Locations: locations("jdb"),
Metadata: metadata("java-binary-jdk", "java"),
Metadata: metadata("java-binary-openjdk-fallthrough", "jdb"),
},
},
{
@@ -985,6 +1007,28 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
Metadata: metadata("consul-binary"),
},
},
{
logicalFixture: "vault/1.20.2/linux-amd64",
expected: pkg.Package{
Name: "github.com/hashicorp/vault",
Version: "1.20.2",
Type: "golang",
PURL: "pkg:golang/github.com/hashicorp/vault@1.20.2",
Locations: locations("vault"),
Metadata: metadata("hashicorp-vault-binary"),
},
},
{
logicalFixture: "vault/1.19.4/linux-arm64",
expected: pkg.Package{
Name: "github.com/hashicorp/vault",
Version: "1.19.4",
Type: "golang",
PURL: "pkg:golang/github.com/hashicorp/vault@1.19.4",
Locations: locations("vault"),
Metadata: metadata("hashicorp-vault-binary"),
},
},
{
logicalFixture: "erlang/25.3.2.6/linux-amd64",
expected: pkg.Package{
@@ -1463,8 +1507,8 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
Class: "foo-binary",
FileGlob: "**/foo",
EvidenceMatcher: binutils.FileContentsVersionMatcher(
`(?m)foobar\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`,
catalogerName,
`(?m)foobar\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`,
),
Package: "foo",
PURL: mustPURL("pkg:generic/foo@version"),
@@ -1521,7 +1565,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
binutils.Classifier{
Class: "foo-binary",
FileGlob: "**/foo",
EvidenceMatcher: binutils.FileContentsVersionMatcher(`(?m)not there`, catalogerName),
EvidenceMatcher: binutils.FileContentsVersionMatcher(catalogerName, `(?m)not there`),
Package: "foo",
PURL: mustPURL("pkg:generic/foo@version"),
CPEs: singleCPE("cpe:2.3:a:foo:foo:*:*:*:*:*:*:*:*"),
@@ -1739,7 +1783,7 @@ func TestCatalogerConfig_MarshalJSON(t *testing.T) {
{
Class: "class",
FileGlob: "glob",
EvidenceMatcher: binutils.FileContentsVersionMatcher(".thing", catalogerName),
EvidenceMatcher: binutils.FileContentsVersionMatcher(catalogerName, ".thing"),
Package: "pkg",
PURL: packageurl.PackageURL{
Type: "type",
+22 -73
View File
@@ -28,11 +28,11 @@ func DefaultClassifiers() []binutils.Classifier {
// ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5) [x86_64-linux]
`(?m)ruby (?P<version>[0-9]+\.[0-9]+\.[0-9]+((p|preview|rc|dev)[0-9]*)?) `)
return []binutils.Classifier{
classifiers := []binutils.Classifier{
{
Class: "python-binary",
FileGlob: "**/python*",
EvidenceMatcher: binutils.EvidenceMatchers(
EvidenceMatcher: binutils.MatchAny(
// try to find version information from libpython shared libraries
binutils.SharedLibraryLookup(
`^libpython[0-9]+(?:\.[0-9]+)+[a-z]?\.so.*$`,
@@ -98,7 +98,7 @@ func DefaultClassifiers() []binutils.Classifier {
{
Class: "redis-binary",
FileGlob: "**/redis-server",
EvidenceMatcher: binutils.EvidenceMatchers(
EvidenceMatcher: binutils.MatchAny(
// matches most recent versions of redis (~v7), e.g. "7.0.14buildkitsandbox-1702957741000000000"
m.FileContentsVersionMatcher(`[^\d](?P<version>\d+.\d+\.\d+)buildkitsandbox-\d+`),
// matches against older versions of redis (~v3 - v6), e.g. "4.0.11841ce7054bd9-1542359302000000000"
@@ -113,73 +113,10 @@ func DefaultClassifiers() []binutils.Classifier {
cpe.Must("cpe:2.3:a:redis:redis:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
{
Class: "java-binary-openjdk",
FileGlob: "**/java",
EvidenceMatcher: binutils.MatchExcluding(
binutils.EvidenceMatchers(
m.FileContentsVersionMatcher(
// [NUL]openjdk[NUL]java[NUL]0.0[NUL]11.0.17+8-LTS[NUL]
// [NUL]openjdk[NUL]java[NUL]1.8[NUL]1.8.0_352-b08[NUL]
`(?m)\x00openjdk\x00java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>[0-9]+[^\x00]+)\x00`),
m.FileContentsVersionMatcher(
// arm64 versions: [NUL]0.0[NUL][NUL][NUL][NUL][NUL]11.0.22+7[NUL][NUL][NUL][NUL][NUL][NUL][NUL]openjdk[NUL]java[NUL]
`(?m)\x00(?P<release>[0-9]+[.0-9]*)\x00+(?P<version>[0-9]+[^\x00]+)\x00+openjdk\x00java`),
),
// don't match graalvm
"-jvmci-",
),
Package: "java/jre",
PURL: mustPURL("pkg:generic/java/jre@version"),
// TODO the updates might need to be part of the CPE Attributes, like: 1.8.0:update152
CPEs: singleCPE("cpe:2.3:a:oracle:openjdk:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-ibm",
FileGlob: "**/java",
EvidenceMatcher: m.FileContentsVersionMatcher(
// [NUL]java[NUL]1.8[NUL][NUL][NUL][NUL]1.8.0-foreman_2022_09_22_15_30-b00[NUL]
`(?m)\x00java\x00(?P<release>[0-9]+[.0-9]+)\x00{4}(?P<version>[0-9]+[-._a-zA-Z0-9]+)\x00`),
Package: "java/jre",
PURL: mustPURL("pkg:generic/java/jre@version"),
CPEs: singleCPE("cpe:2.3:a:ibm:java:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-oracle",
FileGlob: "**/java",
EvidenceMatcher: binutils.MatchExcluding(
m.FileContentsVersionMatcher(
// [NUL]19.0.1+10-21[NUL]
`(?m)\x00(?P<version>[0-9]+[.0-9]+[+][-0-9]+)\x00`),
// don't match openjdk
`\x00openjdk\x00`,
),
Package: "java/jre",
PURL: mustPURL("pkg:generic/java/jre@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:jre:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-graalvm",
FileGlob: "**/java",
EvidenceMatcher: m.FileContentsVersionMatcher(
`(?m)\x00(?P<version>[0-9]+[.0-9]+[.0-9]+\+[0-9]+-jvmci-[0-9]+[.0-9]+-b[0-9]+)\x00`),
Package: "java/graalvm",
PURL: mustPURL("pkg:generic/java/graalvm@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:graalvm:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-jdk",
FileGlob: "**/jdb",
EvidenceMatcher: m.FileContentsVersionMatcher(
`(?m)\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\+[0-9]+)?([-._a-zA-Z0-9]+)?)\x00`),
Package: "java/jdk",
PURL: mustPURL("pkg:generic/java/jdk@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:jdk:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "nodejs-binary",
FileGlob: "**/node",
EvidenceMatcher: binutils.EvidenceMatchers(
EvidenceMatcher: binutils.MatchAny(
// [NUL]node v0.10.48[NUL]
// [NUL]v0.12.18[NUL]
// [NUL]v4.9.1[NUL]
@@ -221,7 +158,7 @@ func DefaultClassifiers() []binutils.Classifier {
{
Class: "haproxy-binary",
FileGlob: "**/haproxy",
EvidenceMatcher: binutils.EvidenceMatchers(
EvidenceMatcher: binutils.MatchAny(
m.FileContentsVersionMatcher(`(?m)version (?P<version>[0-9]+\.[0-9]+(\.|-dev|-rc)[0-9]+)(-[a-z0-9]{7})?, released 20`),
m.FileContentsVersionMatcher(`(?m)HA-Proxy version (?P<version>[0-9]+\.[0-9]+(\.|-dev)[0-9]+)`),
m.FileContentsVersionMatcher(`(?m)(?P<version>[0-9]+\.[0-9]+(\.|-dev)[0-9]+)-[0-9a-zA-Z]{7}.+HAProxy version`),
@@ -303,7 +240,7 @@ func DefaultClassifiers() []binutils.Classifier {
{
Class: "mysql-binary",
FileGlob: "**/mysql",
EvidenceMatcher: binutils.EvidenceMatchers(
EvidenceMatcher: binutils.MatchAny(
// shutdown[NUL]8.0.37[NUL][NUL][NUL][NUL][NUL]mysql_real_esc
m.FileContentsVersionMatcher(`\x00(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)\x00+mysql`),
// /export/home/pb2/build/sb_0-26781090-1516292385.58/release/mysql-8.0.4-rc/mysys_ssl/my_default.cc
@@ -380,7 +317,7 @@ func DefaultClassifiers() []binutils.Classifier {
{
Class: "ruby-binary",
FileGlob: "**/ruby",
EvidenceMatcher: binutils.EvidenceMatchers(
EvidenceMatcher: binutils.MatchAny(
rubyMatcher,
binutils.SharedLibraryLookup(
// try to find version information from libruby shared libraries
@@ -394,7 +331,7 @@ func DefaultClassifiers() []binutils.Classifier {
{
Class: "erlang-binary",
FileGlob: "**/erlexec",
EvidenceMatcher: binutils.EvidenceMatchers(
EvidenceMatcher: binutils.MatchAny(
m.FileContentsVersionMatcher(
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
@@ -411,7 +348,7 @@ func DefaultClassifiers() []binutils.Classifier {
{
Class: "erlang-alpine-binary",
FileGlob: "**/beam.smp",
EvidenceMatcher: binutils.EvidenceMatchers(
EvidenceMatcher: binutils.MatchAny(
m.FileContentsVersionMatcher(
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
@@ -432,7 +369,7 @@ func DefaultClassifiers() []binutils.Classifier {
{
Class: "erlang-library",
FileGlob: "**/liberts_internal.a",
EvidenceMatcher: binutils.EvidenceMatchers(
EvidenceMatcher: binutils.MatchAny(
m.FileContentsVersionMatcher(
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
@@ -511,6 +448,16 @@ func DefaultClassifiers() []binutils.Classifier {
PURL: mustPURL("pkg:golang/github.com/hashicorp/consul@version"),
CPEs: singleCPE("cpe:2.3:a:hashicorp:consul:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "hashicorp-vault-binary",
FileGlob: "**/vault",
EvidenceMatcher: m.FileContentsVersionMatcher(
// revoke1.18.0
`(?m)revoke(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
Package: "github.com/hashicorp/vault",
PURL: mustPURL("pkg:golang/github.com/hashicorp/vault@version"),
CPEs: singleCPE("cpe:2.3:a:hashicorp:vault:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "nginx-binary",
FileGlob: "**/nginx",
@@ -681,6 +628,8 @@ func DefaultClassifiers() []binutils.Classifier {
CPEs: singleCPE("cpe:2.3:a:google:chrome:*:*:*:*:*:*:*:*"),
},
}
return append(classifiers, defaultJavaClassifiers()...)
}
// singleCPE returns a []cpe.CPE with Source: Generated based on the cpe string or panics if the
@@ -0,0 +1,196 @@
package binary
import (
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/pkg/cataloger/internal/binutils"
)
//nolint:funlen
func defaultJavaClassifiers() []binutils.Classifier {
m := binutils.ContextualEvidenceMatchers{CatalogerName: catalogerName}
return []binutils.Classifier{
{
Class: "java-binary",
FileGlob: "**/java",
EvidenceMatcher: binutils.BranchingEvidenceMatcher([]binutils.Classifier{
{
Class: "java-binary-graalvm",
EvidenceMatcher: m.FileContentsVersionMatcher(
`(?m)\x00(?P<version>[0-9]+[.0-9]+[.0-9]+\+[0-9]+-jvmci-[0-9]+[.0-9]+-b[0-9]+)\x00`),
Package: "graalvm",
PURL: mustPURL("pkg:generic/oracle/graalvm@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:graalvm:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-openjdk-zulu",
EvidenceMatcher: binutils.MatchAll(
binutils.MatchPath(`**/*zulu*/**`),
binutils.MatchAny(
m.FileContentsVersionMatcher(
// [NUL]openjdk[NUL]java[NUL]0.0[NUL]11.0.17+8-LTS[NUL]
`(?m)\x00java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>[0-9]+[^\x00]+)\x00`),
m.FileContentsVersionMatcher(
// arm64 versions: [NUL]0.0[NUL][NUL][NUL][NUL][NUL]11.0.22+7[NUL][NUL][NUL][NUL][NUL][NUL][NUL]openjdk[NUL]java[NUL]
`(?m)\x00(?P<release>[0-9]+[.0-9]*)\x00+(?P<version>[0-9]+[^\x00]+)\x00+(openjdk|java)`),
),
),
Package: "zulu",
PURL: mustPURL("pkg:generic/azul/zulu@version"),
CPEs: singleCPE("cpe:2.3:a:azul:zulu:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-openjdk-with-update",
EvidenceMatcher: binutils.MatchAny(
m.FileContentsVersionMatcher(
`openjdk`,
// [NUL]openjdk[NUL]java[NUL]1.8[NUL]1.8.0_352-b08[NUL]
`(?m)java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>(?<primary>[0-9]+[^\x00]+)_(?<update>[^\x00]+)-[^\x00]+)\x00`),
m.FileContentsVersionMatcher(
`openjdk`,
// arm64 versions: [NUL]0.0[NUL][NUL][NUL][NUL][NUL]1.8.0_352-b08[NUL][NUL][NUL][NUL][NUL][NUL][NUL]openjdk[NUL]java[NUL]
`(?m)\x00(?P<release>[0-9]+[.0-9]*)\x00+(?P<version>(?<primary>[0-9]+[^\x00]+)_(?<update>[^\x00]+)-[^\x00]+)\x00+openjdk\x00java`),
),
Package: "openjdk",
PURL: mustPURL("pkg:generic/oracle/openjdk@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:openjdk:{{.primary}}:update{{.update}}:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-openjdk",
EvidenceMatcher: binutils.MatchAny(
m.FileContentsVersionMatcher(
// [NUL]openjdk[NUL]java[NUL]0.0[NUL]11.0.17+8-LTS[NUL]
`(?m)\x00openjdk\x00java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>[0-9]+[^\x00]+)\x00`),
m.FileContentsVersionMatcher(
// arm64 versions: [NUL]0.0[NUL][NUL][NUL][NUL][NUL]11.0.22+7[NUL][NUL][NUL][NUL][NUL][NUL][NUL]openjdk[NUL]java[NUL]
`(?m)\x00(?P<release>[0-9]+[.0-9]*)\x00+(?P<version>[0-9]+[^\x00]+)\x00+openjdk\x00java`),
),
Package: "openjdk",
PURL: mustPURL("pkg:generic/oracle/openjdk@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:openjdk:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-ibm",
EvidenceMatcher: binutils.MatchAll(
binutils.MatchAny(
binutils.MatchPath("**/ibm/**"),
binutils.SharedLibraryLookup(
`^libjli\.so$`,
m.FileContentsVersionMatcher("IBM_JAVA")),
),
m.FileContentsVersionMatcher(
// [NUL]java[NUL]1.8[NUL][NUL][NUL]1.8.0-foreman_2022_01_20_09_33-b00[NUL]
`(?m)\x00java\x00+(?P<release>[0-9]+[.0-9]+)\x00+(?P<version>[0-9]+[-._a-zA-Z0-9]+)\x00`),
),
Package: "java",
PURL: mustPURL("pkg:generic/ibm/java@version"),
CPEs: singleCPE("cpe:2.3:a:ibm:java:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-openjdk-fallthrough",
EvidenceMatcher: m.FileContentsVersionMatcher(
"openjdk",
// [NUL]19.0.1+10-21[NUL]
`(?m)\x00(?P<version>[0-9]+[.0-9]+[+][-0-9]+)\x00`,
),
Package: "jre",
PURL: mustPURL("pkg:generic/oracle/jre@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:jre:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-oracle",
EvidenceMatcher: m.FileContentsVersionMatcher(
// [NUL]19.0.1+10-21[NUL]
// java[NUL]1.8[NUL]1.8.0_451-b10
`(?m)\x00(?P<version>[0-9]+\.[0-9]+\.[-._+a-zA-Z0-9]+)\x00`,
),
Package: "jre",
PURL: mustPURL("pkg:generic/oracle/jre@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:jre:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
}...),
},
{
Class: "java-jdb-binary",
FileGlob: "**/jdb",
EvidenceMatcher: binutils.BranchingEvidenceMatcher([]binutils.Classifier{
{
Class: "java-binary-graalvm",
EvidenceMatcher: m.FileContentsVersionMatcher(
`(?m)\x00(?P<version>[0-9]+[.0-9]+[.0-9]+\+[0-9]+-jvmci-[0-9]+[.0-9]+-b[0-9]+)\x00`),
Package: "graalvm",
PURL: mustPURL("pkg:generic/oracle/graalvm@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:graalvm_for_jdk:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-jdb-binary-openjdk",
EvidenceMatcher: binutils.MatchAll(
m.FileContentsVersionMatcher(
// [NUL]openjdk[NUL]java[NUL]0.0[NUL]11.0.17+8-LTS[NUL]
// [NUL]openjdk[NUL]java[NUL]1.8[NUL]1.8.0_352-b08[NUL]
`(?m)\x00openjdk\x00java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>[0-9]+[^\x00]+)\x00`),
m.FileContentsVersionMatcher(
// arm64 versions: [NUL]0.0[NUL][NUL][NUL][NUL][NUL]11.0.22+7[NUL][NUL][NUL][NUL][NUL][NUL][NUL]openjdk[NUL]java[NUL]
`(?m)\x00(?P<release>[0-9]+[.0-9]*)\x00+(?P<version>[0-9]+[^\x00]+)\x00+openjdk\x00java`),
),
Package: "openjdk",
PURL: mustPURL("pkg:generic/oracle/openjdk@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:openjdk:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "jdb-binary-openjdk-zulu",
EvidenceMatcher: binutils.MatchAll(
binutils.MatchPath("**/*zulu*/**"),
binutils.MatchAny(
m.FileContentsVersionMatcher(
// [NUL]openjdk[NUL]java[NUL]0.0[NUL]11.0.17+8-LTS[NUL]
`(?m)\x00openjdk\x00java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>[0-9]+[^\x00]+)\x00`),
m.FileContentsVersionMatcher(
// arm64 versions: [NUL]0.0[NUL][NUL][NUL][NUL][NUL]11.0.22+7[NUL][NUL][NUL][NUL][NUL][NUL][NUL]openjdk[NUL]java[NUL]
`(?m)\x00(?P<release>[0-9]+[.0-9]*)\x00+(?P<version>[0-9]+[^\x00]+)\x00+openjdk\x00java`),
),
),
Package: "zulu",
PURL: mustPURL("pkg:generic/azul/zulu@version"),
CPEs: singleCPE("cpe:2.3:a:azul:zulu:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-sdk-binary-ibm",
EvidenceMatcher: binutils.MatchAll(
binutils.MatchAny(
binutils.MatchPath("**/ibm/**"),
binutils.SharedLibraryLookup(
`^libjli\.so$`,
m.FileContentsVersionMatcher("IBM_JAVA")),
),
m.FileContentsVersionMatcher(
// [NUL]java[NUL]./lib/tools.jar./lib/sa-jdi.jar./classes.-J-ms8m[NUL][NUL]1.8[NUL][NUL][NUL]1.8.0-foreman_2022_01_20_09_33-b00[NUL]
`(?m)\x00java\x00.+?\x00(?P<version>[0-9]+[-._a-zA-Z0-9]+)\x00`),
),
Package: "java_sdk",
PURL: mustPURL("pkg:generic/ibm/java_sdk@version"),
CPEs: singleCPE("cpe:2.3:a:ibm:java_sdk:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-openjdk-fallthrough",
EvidenceMatcher: binutils.MatchAll(
m.FileContentsVersionMatcher(
"openjdk",
`(?m)\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\+[0-9]+)?([-._a-zA-Z0-9]+)?)\x00`),
),
Package: "openjdk",
PURL: mustPURL("pkg:generic/oracle/openjdk@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:openjdk:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "java-binary-jdk",
EvidenceMatcher: m.FileContentsVersionMatcher(
`(?m)\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\+[0-9]+)?([-._a-zA-Z0-9]+)?)\x00`),
Package: "jdk",
PURL: mustPURL("pkg:generic/oracle/jdk@version"),
CPEs: singleCPE("cpe:2.3:a:oracle:jdk:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
}...),
},
}
}
+1 -1
View File
@@ -14,5 +14,5 @@ type EvidenceMatcher = binutils.EvidenceMatcher
func FileContentsVersionMatcher(
pattern string,
) EvidenceMatcher {
return binutils.FileContentsVersionMatcher(pattern, catalogerName)
return binutils.FileContentsVersionMatcher(catalogerName, pattern)
}
@@ -0,0 +1,11 @@
name: vault
offset: 191891817
length: 420
snippetSha256: fd8eb7979e1e7bbc254f2f7a26f6a70ecb479cc4f50c804f3b0789bc0e229097
fileSha256: a4754a343e619adef87a1d7e1368a0709ba29802fefbe8d70105c11085becd43
### byte snippet to follow ###
ctstreamPragma</a>.
:httpssocks Locked%s.logCT_LOGLOCAL0@level[INFO][WARN]env:///v1/%sDELETEcreateErrorserrorsclient/data/lookupactualAcceptregionawskmsocikmspkcs11%s%s%scloud:%s.%s:revoke1.19.4)(nil))(%#v) {...}frenchCommonArabicBrahmiCarianChakmaCopticGothicHangulHatranHebrewKaithiKhojkiLepchaLycianLydianRejangSyriacTai_LeTangsaTangutTeluguThaanaWanchoYezidiHyphen\u%04x\U%08xgetentpasswd390625%s
%s
%q: %wnumber\uff
@@ -0,0 +1,9 @@
name: vault
offset: 213670425
length: 220
snippetSha256: d9b23916d00e8085a4066974641ef77962f2e0aae6f4244688d2c4fe4286c92b
fileSha256: fb484f1b458e5d2fd28270b406a8b26b28d040dddcaa1d099aa9ee4ac927b730
### byte snippet to follow ###
ctstreamPragma</a>.
:httpssocks Locked%s.logCT_LOGLOCAL0@level[INFO][WARN]env:///v1/%sDELETEcreateErrorserrorsclient/data/lookupactualAcceptregionawskmsocikmspkcs11%s%s%scloud:%s.%s:revoke1.20.2)(nil))(%#v) {...}frenchCo
@@ -194,6 +194,25 @@ from-images:
platform: linux/amd64
paths:
- /opt/ibm/java/jre/bin/java
- /opt/ibm/java/jre/lib/amd64/jli/libjli.so
- name: java-ibm-8-jre
version: 1.8.0_451
images:
- ref: ibmjava:8-jre@sha256:3588cd1cc9b8646fe03b3b15210e69b1b520f1321f8518b69c0e7013d702fd23
platform: linux/amd64
paths:
- /opt/ibm/java/jre/bin/java
- /opt/ibm/java/jre/lib/amd64/jli/libjli.so
- name: java-ibm-8-sdk-alpine
version: 1.8.0_321
images:
- ref: ibmjava:8-sdk-alpine@sha256:4f8ad2029e78f7b91721745a77fc6011a7c0e09b9edeffb6b20b6ec34a6e63cd
platform: linux/amd64
paths:
- /opt/ibm/java/bin/jdb
- /opt/ibm/java/lib/amd64/jli/libjli.so
- version: 10.6.15
images:
@@ -320,6 +339,23 @@ from-images:
paths:
- /usr/local/bin/node
- name: java-jdk-oracle
version: 1.8.0_451-b10
images:
- ref: container-registry.oracle.com/java/jdk:8u451-oraclelinux8@sha256:f9c980e52853bd0a8815ad908c9a4025ed68cb52f31f3b8cd0cd442ee367bfd1
platform: linux/amd64
paths:
- /usr/java/jdk-8/bin/java
- /usr/java/jdk-8/bin/jdb
- name: java-jre-oracle-sdk
version: 1.8.0_451-b10
images:
- ref: container-registry.oracle.com/java/serverjre:1.8.0_451@sha256:fe78fe3efd292dceb5685882ce1b13eb78492f383ccfd52a1b88a4f755b9d996
platform: linux/amd64
paths:
- /usr/java/jdk-8/bin/java
- name: java-jre-openjdk
version: 1.8.0_352-b08
images:
@@ -688,6 +724,20 @@ from-images:
paths:
- /bin/consul
- version: 1.20.2
images:
- ref: hashicorp/vault@sha256:5cd2003247e0a574a66c66aee1916b1e9e7f99640298f2e61271a8842d2d2a19
platform: linux/amd64
paths:
- /bin/vault
- version: 1.19.4
images:
- ref: hashicorp/vault@sha256:b5f675b0bf681568cd7354c697fe4ce953024312d6d23ee7216deda60c192bad
platform: linux/arm64
paths:
- /bin/vault
- version: 3.0.2
images:
- ref: fluent/fluent-bit:3.0.2-amd64@sha256:7e6fe8efd51dda0739e355f58bf5e3b1623cbf2d4a23c06c7a365d9553e2d242
+2 -2
View File
@@ -133,6 +133,7 @@ func addLicenses(ctx context.Context, resolver file.Resolver, dbLocation file.Lo
if len(licenseStrs) == 0 {
sr, sl := fetchCopyrightContents(resolver, dbLocation, metadata)
if sr != nil && sl != nil {
defer internal.CloseAndLogError(sr, sl.AccessPath)
p.Licenses.Add(pkg.NewLicensesFromReadCloserWithContext(ctx, file.NewLocationReadCloser(*sl, sr))...)
}
}
@@ -292,11 +293,10 @@ func fetchCopyrightContents(resolver file.Resolver, dbLocation file.Location, m
return nil, nil
}
reader, err := resolver.FileContentsByLocation(*location)
reader, err := resolver.FileContentsByLocation(*location) //nolint:gocritic // since we're returning the reader, it's up to the caller to close it
if err != nil {
log.Tracef("failed to fetch deb copyright contents (package=%s): %s", m.Package, err)
}
defer internal.CloseAndLogError(reader, location.RealPath)
l := location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)
-1
View File
@@ -98,7 +98,6 @@ func findLibmanJSON(resolver file.Resolver, depsJSON file.Location) (*libmanJSON
if err != nil {
return nil, err
}
internal.CloseAndLogError(reader, loc.RealPath)
lj, err := newLibmanJSON(file.NewLocationReadCloser(*loc, reader))
if err != nil {
@@ -0,0 +1,43 @@
package binutils
import (
"io"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/syft/internal/unionreader"
"github.com/anchore/syft/syft/pkg"
)
// BranchingEvidenceMatcher loads the contents of the reader into memory, assuming that all
// classifier matchers are going to be reading the same file, e.g. a "java" binary, continuing to
// try classifier EvidenceMatcher until the first set of packages is found
func BranchingEvidenceMatcher(classifiers ...Classifier) EvidenceMatcher {
return func(_ Classifier, context MatcherContext) ([]pkg.Package, error) {
// we are scanning the same contents multiple times, so read it into memory for a reader that can reset
rdr, err := getReader(context)
if err != nil {
return nil, err
}
defer internal.CloseAndLogError(rdr, context.Location.RealPath)
if err != nil {
return nil, err
}
for _, c := range classifiers {
pkgs, err := c.EvidenceMatcher(c, MatcherContext{
Resolver: context.Resolver,
Location: context.Location,
GetReader: func(_ MatcherContext) (unionreader.UnionReader, error) {
_, err := rdr.Seek(0, io.SeekStart)
if err != nil {
return nil, err
}
return rdr, nil
},
})
if len(pkgs) > 0 || err != nil {
return pkgs, err
}
}
return nil, nil
}
}
@@ -0,0 +1,95 @@
package binutils
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/internal/unionreader"
)
func Test_BranchingMatcher(t *testing.T) {
matchingTest := FileContentsVersionMatcher("", `my-verison:(?<version>\d+\.\d+)`)
notMatchingTest := MatchPath("**/not-version*")
tests := []struct {
name string
matcher EvidenceMatcher
expectedPackageNames []string
}{
{
name: "not matching",
matcher: BranchingEvidenceMatcher(
Classifier{
EvidenceMatcher: MatchAll(
notMatchingTest,
matchingTest,
),
Package: "a-pkg",
},
),
expectedPackageNames: nil,
},
{
name: "both match",
matcher: BranchingEvidenceMatcher(
Classifier{
EvidenceMatcher: matchingTest,
Package: "a-pkg",
},
Classifier{
EvidenceMatcher: matchingTest,
Package: "b-pkg",
},
),
expectedPackageNames: []string{"a-pkg"},
},
{
name: "first-does-not-match",
matcher: BranchingEvidenceMatcher(
Classifier{
EvidenceMatcher: MatchAll(
notMatchingTest,
matchingTest,
),
Package: "b-pkg",
},
Classifier{
EvidenceMatcher: matchingTest,
Package: "c-pkg",
},
),
expectedPackageNames: []string{"c-pkg"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
resolver := file.NewMockResolverForPaths("test-fixtures/version.txt", "test-fixtures/version-parts.txt")
locs, err := resolver.FilesByGlob("**/version.txt")
require.NoError(t, err)
require.Len(t, locs, 1)
loc := locs[0]
rdr, err := resolver.FileContentsByLocation(loc)
require.NoError(t, err)
urdr, err := unionreader.GetUnionReader(rdr)
require.NoError(t, err)
pkgs, err := test.matcher(Classifier{
Package: "a-pkg",
}, MatcherContext{
Resolver: resolver,
Location: loc,
GetReader: func(resolver MatcherContext) (unionreader.UnionReader, error) {
return urdr, nil
},
})
require.NoError(t, err)
var got []string
for i := range pkgs {
got = append(got, pkgs[i].Name)
}
require.EqualValues(t, test.expectedPackageNames, got)
})
}
}
@@ -8,11 +8,14 @@ import (
"encoding/json"
"fmt"
"io"
"maps"
"regexp"
"strconv"
"strings"
"text/template"
"github.com/bmatcuk/doublestar/v4"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
@@ -71,7 +74,8 @@ func (cfg Classifier) MarshalJSON() ([]byte, error) {
return json.Marshal(m)
}
// EvidenceMatcher is a function called to catalog Packages that match some sort of evidence
// EvidenceMatcher is a function called to identify based on some sort of evidence in the filesystem contents.
// A non-nil return value indicates a successful match, regardless of packages being returned.
type EvidenceMatcher func(classifier Classifier, context MatcherContext) ([]pkg.Package, error)
type MatcherContext struct {
@@ -80,13 +84,16 @@ type MatcherContext struct {
GetReader func(resolver MatcherContext) (unionreader.UnionReader, error)
}
func EvidenceMatchers(matchers ...EvidenceMatcher) EvidenceMatcher {
// MatchAny returns a combined evidence matcher that returns results from the first
// matcher that returns results
func MatchAny(matchers ...EvidenceMatcher) EvidenceMatcher {
return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) {
for _, matcher := range matchers {
match, err := matcher(classifier, context)
if err != nil {
return nil, err
}
// only return when results
if match != nil {
return match, nil
}
@@ -95,6 +102,23 @@ func EvidenceMatchers(matchers ...EvidenceMatcher) EvidenceMatcher {
}
}
// MatchAll executes all matchers until one returns nil results, only returning the final results
func MatchAll(matchers ...EvidenceMatcher) EvidenceMatcher {
return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) {
var out []pkg.Package
for _, matcher := range matchers {
match, err := matcher(classifier, context)
if match == nil || err != nil {
return nil, err
}
if len(match) > 0 {
out = match
}
}
return out, nil
}
}
type ContextualEvidenceMatchers struct {
CatalogerName string
}
@@ -103,8 +127,8 @@ func (c ContextualEvidenceMatchers) FileNameTemplateVersionMatcher(fileNamePatte
return FileNameTemplateVersionMatcher(fileNamePattern, contentTemplate, c.CatalogerName)
}
func (c ContextualEvidenceMatchers) FileContentsVersionMatcher(pattern string) EvidenceMatcher {
return FileContentsVersionMatcher(pattern, c.CatalogerName)
func (c ContextualEvidenceMatchers) FileContentsVersionMatcher(patterns ...string) EvidenceMatcher {
return FileContentsVersionMatcher(c.CatalogerName, patterns...)
}
func FileNameTemplateVersionMatcher(fileNamePattern, contentTemplate, catalogerName string) EvidenceMatcher {
@@ -156,17 +180,36 @@ func FileNameTemplateVersionMatcher(fileNamePattern, contentTemplate, catalogerN
}
}
func FileContentsVersionMatcher(pattern, catalogerName string) EvidenceMatcher {
pat := regexp.MustCompile(pattern)
// FileContentsVersionMatcher will match all provided patterns, extracting named capture groups from each pattern, overwriting earlier results
func FileContentsVersionMatcher(catalogerName string, patterns ...string) EvidenceMatcher {
if len(patterns) == 0 {
panic("must specify at least one pattern")
}
var pats []*regexp.Regexp
for _, pattern := range patterns {
pats = append(pats, regexp.MustCompile(pattern))
}
return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) {
contents, err := getReader(context)
if err != nil {
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
}
var matchMetadata map[string]string
matchMetadata, err := internal.MatchNamedCaptureGroupsFromReader(pat, contents)
if err != nil {
return nil, fmt.Errorf("unable to match version: %w", err)
for _, pat := range pats {
contents, err := getReader(context)
if err != nil {
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
}
match, err := internal.MatchNamedCaptureGroupsFromReader(pat, contents)
if err != nil {
return nil, fmt.Errorf("unable to match version: %w", err)
}
if match == nil {
return nil, nil
}
if matchMetadata == nil {
matchMetadata = match
} else {
maps.Copy(matchMetadata, match)
}
}
// Convert {major: 1, minor: 2, patch: 3} to "1.2.3"
@@ -187,6 +230,10 @@ func FileContentsVersionMatcher(pattern, catalogerName string) EvidenceMatcher {
p := NewClassifierPackage(classifier, context.Location, matchMetadata, catalogerName)
if p == nil {
if matchMetadata != nil {
// if we had a successful metadata match, but no packages, return a successful match result
return []pkg.Package{}, nil
}
return nil, nil
}
@@ -194,29 +241,6 @@ func FileContentsVersionMatcher(pattern, catalogerName string) EvidenceMatcher {
}
}
// MatchExcluding tests the provided regular expressions against the file, and if matched, DOES NOT return
// anything that the matcher would otherwise return
func MatchExcluding(matcher EvidenceMatcher, contentPatternsToExclude ...string) EvidenceMatcher {
var nonMatchPatterns []*regexp.Regexp
for _, p := range contentPatternsToExclude {
nonMatchPatterns = append(nonMatchPatterns, regexp.MustCompile(p))
}
return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) {
contents, err := getReader(context)
if err != nil {
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
}
matches, err := internal.MatchAnyFromReader(contents, nonMatchPatterns...)
if err != nil {
return nil, fmt.Errorf("unable to match content: %w", err)
}
if matches {
return nil, nil
}
return matcher(classifier, context)
}
}
func SharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher EvidenceMatcher) EvidenceMatcher {
pat := regexp.MustCompile(sharedLibraryPattern)
return func(classifier Classifier, context MatcherContext) (packages []pkg.Package, _ error) {
@@ -234,16 +258,19 @@ func SharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher Evide
return nil, err
}
for _, libraryLocation := range locations {
// create a new resolver without the cached context lookup -- this is decidedly a different file
newResolver := MatcherContext{
Resolver: context.Resolver,
Location: libraryLocation,
GetReader: context.GetReader,
Resolver: context.Resolver,
Location: libraryLocation,
}
newResolver.Location = libraryLocation
pkgs, err := sharedLibraryMatcher(classifier, newResolver)
if err != nil {
return nil, err
}
// not a successful match
if pkgs == nil {
continue
}
for _, p := range pkgs {
// set the source binary as the first location
locationSet := file.NewLocationSet(context.Location)
@@ -260,12 +287,28 @@ func SharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher Evide
}
packages = append(packages, p)
}
// return non-nil package results as a successful match indication if the evidence matcher returned a successful match indication
if packages == nil {
packages = pkgs
}
}
}
return packages, nil
}
}
func MatchPath(path string) EvidenceMatcher {
if !doublestar.ValidatePattern(path) {
panic("invalid pattern")
}
return func(_ Classifier, context MatcherContext) ([]pkg.Package, error) {
if doublestar.MatchUnvalidated(path, context.Location.RealPath) {
return []pkg.Package{}, nil // return non-nil
}
return nil, nil
}
}
func getReader(context MatcherContext) (unionreader.UnionReader, error) {
if context.GetReader != nil {
return context.GetReader(context)
@@ -1,9 +1,12 @@
package binutils
import (
"bytes"
"reflect"
"text/template"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
@@ -21,8 +24,8 @@ func NewClassifierPackage(classifier Classifier, location file.Location, matchMe
var cpes []cpe.CPE
for _, c := range classifier.CPEs {
c.Attributes.Version = version
c.Attributes.Update = update
c.Attributes.Version = templatedUpdate(c.Attributes.Version, matchMetadata, version)
c.Attributes.Update = templatedUpdate(c.Attributes.Update, matchMetadata, update)
cpes = append(cpes, c)
}
@@ -55,3 +58,28 @@ func NewClassifierPackage(classifier Classifier, location file.Location, matchMe
return &p
}
func templatedUpdate(providedValue string, matchMetadata map[string]string, defaultValue string) string {
// if no template provided, just use the value directly
if providedValue == "" {
return defaultValue
}
// support templated updates
t, err := template.New("").Option("missingkey=zero").Parse(providedValue)
if err != nil {
log.Debugf("unable to parse classifier template=%q : %w", providedValue, err)
} else {
update := bytes.Buffer{}
err = t.Execute(&update, matchMetadata)
if err != nil {
log.Debugf("unable to render template: %w", err)
} else {
// only use the template result if it's non-empty
providedValue = update.String()
if providedValue != "" {
return providedValue
}
}
}
return defaultValue
}
@@ -27,7 +27,7 @@ func Test_ClassifierCPEs(t *testing.T) {
classifier: Classifier{
Package: "some-app",
FileGlob: "**/version.txt",
EvidenceMatcher: FileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`, "cataloger-name"),
EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)my-verison:(?P<version>[0-9.]+)`),
CPEs: []cpe.CPE{},
},
cpes: nil,
@@ -38,7 +38,7 @@ func Test_ClassifierCPEs(t *testing.T) {
classifier: Classifier{
Package: "some-app",
FileGlob: "**/version.txt",
EvidenceMatcher: FileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`, "cataloger-name"),
EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)my-verison:(?P<version>[0-9.]+)`),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*", cpe.GeneratedSource),
},
@@ -53,7 +53,7 @@ func Test_ClassifierCPEs(t *testing.T) {
classifier: Classifier{
Package: "some-app",
FileGlob: "**/version.txt",
EvidenceMatcher: FileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`, "cataloger-name"),
EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)my-verison:(?P<version>[0-9.]+)`),
CPEs: []cpe.CPE{
cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*", cpe.GeneratedSource),
cpe.Must("cpe:2.3:a:some:apps:*:*:*:*:*:*:*:*", cpe.GeneratedSource),
@@ -70,7 +70,7 @@ func Test_ClassifierCPEs(t *testing.T) {
classifier: Classifier{
Package: "some-app",
FileGlob: "**/version-parts.txt",
EvidenceMatcher: FileContentsVersionMatcher(`(?m)\x00(?P<major>[0-9.]+)\x00(?P<minor>[0-9.]+)\x00(?P<patch>[0-9.]+)\x00`, "cataloger-name"),
EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)\x00(?P<major>[0-9.]+)\x00(?P<minor>[0-9.]+)\x00(?P<patch>[0-9.]+)\x00`),
CPEs: []cpe.CPE{},
},
cpes: nil,
@@ -113,7 +113,7 @@ func TestClassifier_MarshalJSON(t *testing.T) {
classifier: Classifier{
Class: "class",
FileGlob: "glob",
EvidenceMatcher: FileContentsVersionMatcher(".thing", "cataloger-name"),
EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", ".thing"),
Package: "pkg",
PURL: packageurl.PackageURL{
Type: "type",
@@ -168,7 +168,7 @@ func TestFileContentsVersionMatcher(t *testing.T) {
mockGetContent := func(context MatcherContext) (unionreader.UnionReader, error) {
return unionreader.GetUnionReader(io.NopCloser(bytes.NewBufferString(tt.data)))
}
fn := FileContentsVersionMatcher(tt.pattern, "cataloger-name")
fn := FileContentsVersionMatcher("cataloger-name", tt.pattern)
p, err := fn(Classifier{}, MatcherContext{
GetReader: mockGetContent,
})
@@ -61,6 +61,9 @@
"github.com/gofiber/template/django/v3": [
"cpe:2.3:a:gofiber:django:*:*:*:*:*:go:*:*"
],
"github.com/google/nftables": [
"cpe:2.3:a:google:nftables:*:*:*:*:*:go:*:*"
],
"github.com/gookit/goutil": [
"cpe:2.3:a:go_util_project:go_util:*:*:*:*:*:go:*:*"
],
@@ -161,6 +164,9 @@
]
},
"jenkins_plugins": {
"ApicaLoadtest": [
"cpe:2.3:a:jenkins:apica_loadtest:*:*:*:*:*:jenkins:*:*"
],
"DotCi": [
"cpe:2.3:a:jenkins:dotci:*:*:*:*:*:jenkins:*:*"
],
@@ -1339,6 +1345,9 @@
"nomad": [
"cpe:2.3:a:jenkins:nomad:*:*:*:*:*:jenkins:*:*"
],
"nouvola-divecloud": [
"cpe:2.3:a:jenkins:nouvola_divecloud:*:*:*:*:*:jenkins:*:*"
],
"nuget": [
"cpe:2.3:a:jenkins:nuget:*:*:*:*:*:jenkins:*:*"
],
@@ -1919,6 +1928,9 @@
"usemango-runner": [
"cpe:2.3:a:jenkins:usemango_runner:*:*:*:*:*:jenkins:*:*"
],
"vaddy-plugin": [
"cpe:2.3:a:jenkins:vaddy:*:*:*:*:*:jenkins:*:*"
],
"valgrind": [
"cpe:2.3:a:jenkins:valgrind:*:*:*:*:*:jenkins:*:*"
],
@@ -2348,6 +2360,9 @@
"@zxcvbn-ts/core": [
"cpe:2.3:a:zxcvbn-ts_project:zxcvbn-ts:*:*:*:*:*:node.js:*:*"
],
"ContentTools": [
"cpe:2.3:a:getme:contenttools:*:*:*:*:*:node.js:*:*"
],
"Proto": [
"cpe:2.3:a:proto_project:proto:*:*:*:*:*:node.js:*:*"
],
@@ -5552,6 +5567,9 @@
"mustache/mustache": [
"cpe:2.3:a:mustache_project:mustache:*:*:*:*:*:php:*:*"
],
"nitsan/ns-backup": [
"cpe:2.3:a:nitsantech:ns-backup:*:*:*:*:*:typo3:*:*"
],
"phpfastcache/phpfastcache": [
"cpe:2.3:a:phpfastcache:phpfastcache:*:*:*:*:*:*:*:*"
],
@@ -8292,6 +8310,9 @@
"awsm-team": [
"cpe:2.3:a:awsm:awsm_team:*:*:*:*:free:wordpress:*:*"
],
"axle-demo-importer": [
"cpe:2.3:a:axlethemes:axle_demo_importer:*:*:*:*:*:wordpress:*:*"
],
"ays-chatgpt-assistant": [
"cpe:2.3:a:ays-pro:chatgpt_assistant:*:*:*:*:free:wordpress:*:*"
],
@@ -8776,6 +8797,9 @@
"cpe:2.3:a:brizy:brizy:*:*:*:*:free:wordpress:*:*",
"cpe:2.3:a:brizy:brizy:*:*:*:*:pro:wordpress:*:*"
],
"broadstreet": [
"cpe:2.3:a:broadstreetads:broadstreet:*:*:*:*:*:wordpress:*:*"
],
"broken-link-checker": [
"cpe:2.3:a:managewp:broken_link_checker:*:*:*:*:*:wordpress:*:*"
],
@@ -10535,6 +10559,9 @@
"drawblog": [
"cpe:2.3:a:drawblog_project:drawblog:*:*:*:*:*:wordpress:*:*"
],
"drive-folder-embeder": [
"cpe:2.3:a:azumbro:drive_folder_embedder:*:*:*:*:*:wordpress:*:*"
],
"droit-dark-mode": [
"cpe:2.3:a:droitthemes:droit_dark_mode:*:*:*:*:*:wordpress:*:*"
],
@@ -11042,6 +11069,7 @@
"cpe:2.3:a:inisev:enhanced_text_widget:*:*:*:*:*:wordpress:*:*"
],
"enhanced-tooltipglossary": [
"cpe:2.3:a:cminds:cm_tooltip_glossary:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:cminds:tooltip_glossary:*:*:*:*:*:wordpress:*:*"
],
"enqueue-anything": [
@@ -11803,6 +11831,9 @@
"frontier-post": [
"cpe:2.3:a:wpfrontier:frontier_post:*:*:*:*:*:wordpress:*:*"
],
"fs-product-inquiry": [
"cpe:2.3:a:fudugo:fs_product_inquiry:*:*:*:*:*:wordpress:*:*"
],
"fs-shopping-cart": [
"cpe:2.3:a:firestormplugins:fs-shopping-cart:*:*:*:*:*:wordpress:*:*"
],
@@ -11833,6 +11864,9 @@
"furikake": [
"cpe:2.3:a:furikake_project:furikake:*:*:*:*:*:wordpress:*:*"
],
"fusedesk": [
"cpe:2.3:a:jeremyshapiro:fusedesk:*:*:*:*:*:wordpress:*:*"
],
"fusion-builder": [
"cpe:2.3:a:theme-fusion:avada:*:*:*:*:*:wordpress:*:*"
],
@@ -12061,6 +12095,9 @@
"glossary-by-codeat": [
"cpe:2.3:a:codeat:glossary:*:*:*:*:*:wordpress:*:*"
],
"glossy": [
"cpe:2.3:a:croberts:glossy:*:*:*:*:*:wordpress:*:*"
],
"gm-woocommerce-quote-popup": [
"cpe:2.3:a:gravitymaster:product_enquiry_for_woocommerce:*:*:*:*:*:wordpress:*:*"
],
@@ -12285,6 +12322,9 @@
"gtbabel": [
"cpe:2.3:a:gtbabel:gtbabel:*:*:*:*:*:wordpress:*:*"
],
"gtg-advanced-blocks": [
"cpe:2.3:a:gutengeek:free_gutenberg_blocks:*:*:*:*:*:wordpress:*:*"
],
"gtm-server-side": [
"cpe:2.3:a:stape:gtm_server_side:*:*:*:*:*:wordpress:*:*"
],
@@ -12459,6 +12499,9 @@
"homepage-product-organizer-for-woocommerce": [
"cpe:2.3:a:homepage_product_organizer_for_woocommerce_project:homepage_product_organizer_for_woocommerce:*:*:*:*:*:wordpress:*:*"
],
"homerunner-smartcheckout": [
"cpe:2.3:a:coolrunner:homerunner:*:*:*:*:*:wordpress:*:*"
],
"honeypot": [
"cpe:2.3:a:dineshkarki:wp_armour:*:*:*:*:*:wordpress:*:*"
],
@@ -12783,6 +12826,9 @@
"indeed-job-importer": [
"cpe:2.3:a:indeed-job-importer_project:indeed-job-importer:*:*:*:*:*:*:*:*"
],
"index-wp-mysql-for-speed": [
"cpe:2.3:a:plumislandmedia:index_wp_mysql_for_speed:*:*:*:*:*:wordpress:*:*"
],
"indieblocks": [
"cpe:2.3:a:janboddez:indieblocks:*:*:*:*:*:wordpress:*:*"
],
@@ -13099,6 +13145,9 @@
"cpe:2.3:a:joomsky:js_help_desk:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:wiselyhub:js_help_desk:*:*:*:*:*:wordpress:*:*"
],
"js_composer": [
"cpe:2.3:a:wpbakery:page_builder:*:*:*:*:*:wordpress:*:*"
],
"jsmol2wp": [
"cpe:2.3:a:jsmol2wp_project:jsmol2wp:*:*:*:*:*:wordpress:*:*"
],
@@ -13942,7 +13991,8 @@
"cpe:2.3:a:mekshq:meks_flexible_shortcodes:*:*:*:*:*:wordpress:*:*"
],
"meks-smart-author-widget": [
"cpe:2.3:a:mekshq:meks_smart_author_widget:*:*:*:*:*:wordpress:*:*"
"cpe:2.3:a:mekshq:meks_smart_author_widget:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:mekshq:smart_author_widget:*:*:*:*:*:wordpress:*:*"
],
"meks-smart-social-widget": [
"cpe:2.3:a:mekshq:meks_smart_social_widget:*:*:*:*:*:wordpress:*:*"
@@ -14569,6 +14619,9 @@
"note-press": [
"cpe:2.3:a:datainterlock:note_press:*:*:*:*:*:wordpress:*:*"
],
"notice-faq": [
"cpe:2.3:a:notice:notice_faq:*:*:*:*:*:wordpress:*:*"
],
"notices": [
"cpe:2.3:a:notices_project:notices:*:*:*:*:*:wordpress:*:*"
],
@@ -15159,6 +15212,9 @@
"plausible-analytics": [
"cpe:2.3:a:plausible:plausible_analytics:*:*:*:*:*:wordpress:*:*"
],
"play-ht": [
"cpe:2.3:a:hammadh:play.ht:*:*:*:*:*:wordpress:*:*"
],
"player": [
"cpe:2.3:a:web-dorado:spidervplayer:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:web-dorado:web-dorado_spider_video_player:*:*:*:*:*:wordpress:*:*"
@@ -15421,6 +15477,9 @@
"posts-reminder": [
"cpe:2.3:a:lucasgarcia:posts_reminder:*:*:*:*:*:wordpress:*:*"
],
"posts-table-filterable": [
"cpe:2.3:a:pluginus:tableon_-_wordpress_posts_table_filterable:*:*:*:*:*:wordpress:*:*"
],
"posttabs": [
"cpe:2.3:a:posttabs_project:posttabs:*:*:*:*:*:wordpress:*:*"
],
@@ -15816,6 +15875,9 @@
"randomtext": [
"cpe:2.3:a:random_text_project:random_text:*:*:*:*:*:wordpress:*:*"
],
"rapid-cache": [
"cpe:2.3:a:megaoptim:rapid_cache:*:*:*:*:*:wordpress:*:*"
],
"rara-one-click-demo-import": [
"cpe:2.3:a:rarathemes:rara_one_click_demo_import:*:*:*:*:*:wordpress:*:*"
],
@@ -15902,6 +15964,9 @@
"recall-products": [
"cpe:2.3:a:recall-products_project:recall-products:*:*:*:*:*:wordpress:*:*"
],
"recaptcha-jetpack": [
"cpe:2.3:a:bozdoz:recaptcha_jetpack:*:*:*:*:*:wordpress:*:*"
],
"recent-backups": [
"cpe:2.3:a:recent-backups_project:recent-backups:*:*:*:*:*:wordpress:*:*"
],
@@ -18050,6 +18115,9 @@
"tourfic": [
"cpe:2.3:a:themefic:tourfic:*:*:*:*:*:wordpress:*:*"
],
"tourmaster": [
"cpe:2.3:a:goodlayers:tour_master:*:*:*:*:*:wordpress:*:*"
],
"tournamatch": [
"cpe:2.3:a:tournamatch:tournamatch:*:*:*:*:*:wordpress:*:*"
],
@@ -19488,6 +19556,9 @@
"wp-backgrounds-lite": [
"cpe:2.3:a:inoplugs:wp-backgrounds_lite:*:*:*:*:*:wordpress:*:*"
],
"wp-backitup": [
"cpe:2.3:a:wpbackitup:backup_and_restore_wordpress:*:*:*:*:*:wordpress:*:*"
],
"wp-baidu-submit": [
"cpe:2.3:a:wp_baidu_submit_project:wp_baidu_submit:*:*:*:*:*:wordpress:*:*"
],
@@ -19781,6 +19852,9 @@
"wp-easy-contact": [
"cpe:2.3:a:emarketdesign:wp_easy_contact:*:*:*:*:*:wordpress:*:*"
],
"wp-easy-gallery": [
"cpe:2.3:a:plugingarden:wp_easy_gallery:*:*:*:*:*:wordpress:*:*"
],
"wp-easy-pay": [
"cpe:2.3:a:wpeasypay:wp_easypay:*:*:*:*:*:wordpress:*:*"
],
@@ -20180,6 +20254,9 @@
"wp-marketing-automations": [
"cpe:2.3:a:funnelkit:funnelkit_automations:*:*:*:*:*:wordpress:*:*"
],
"wp-masonry-infinite-scroll": [
"cpe:2.3:a:wporbit:wp_masonry_\\\u0026_infinite_scroll:*:*:*:*:*:wordpress:*:*"
],
"wp-media-cleaner": [
"cpe:2.3:a:wp_media_cleaner_project:wp_media_cleaner:*:*:*:*:*:wordpress:*:*"
],
@@ -20756,6 +20833,9 @@
"wp-users-exporter": [
"cpe:2.3:a:wp-users-exporter_project:wp-users-exporter:*:*:*:*:*:wordpress:*:*"
],
"wp-users-masquerade": [
"cpe:2.3:a:lagunaisw:wp_users_masquerade:*:*:*:*:*:wordpress:*:*"
],
"wp-vertical-image-slider": [
"cpe:2.3:a:i13websolution:wordpress_vertical_image_slider:*:*:*:*:*:wordpress:*:*"
],
@@ -21631,6 +21711,9 @@
"posterity": [
"cpe:2.3:a:sktthemes:posterity:*:*:*:*:*:wordpress:*:*"
],
"pressmart": [
"cpe:2.3:a:presslayouts:pressmart:*:*:*:*:*:wordpress:*:*"
],
"regina-lite": [
"cpe:2.3:a:machothemes:regina_lite:*:*:*:*:*:wordpress:*:*"
],
+43 -15
View File
@@ -1,15 +1,18 @@
package java
import (
"cmp"
"context"
"crypto"
"fmt"
"io"
"iter"
"os"
"path"
"slices"
"strings"
"github.com/scylladb/go-set/strset"
"golang.org/x/exp/maps"
"github.com/anchore/syft/internal"
@@ -391,20 +394,32 @@ func (j *archiveParser) discoverMainPackageFromPomInfo(ctx context.Context) (gro
projects, _ := pomProjectByParentPath(j.archivePath, j.location, j.fileManifest.GlobMatch(false, pomXMLGlob))
// map of all the artifacts in the pom properties, in order to chek exact match with the filename
artifactsMap := make(map[string]bool)
artifactsMap := strset.New()
for _, propertiesObj := range properties {
artifactsMap[propertiesObj.ArtifactID] = true
artifactsMap.Add(propertiesObj.ArtifactID)
}
parentPaths := maps.Keys(properties)
slices.Sort(parentPaths)
for _, parentPath := range parentPaths {
propertiesObj := properties[parentPath]
for parentPath, propertiesObj := range sortedIter(properties) {
// the logic for selecting the best name is as follows:
// if we find an artifact id AND group id which are both contained in the filename
// OR if we have an artifact id that exactly matches the filename, prefer this
// OTHERWISE track the first matching pom properties with a pom.xml
// FINALLY return the first matching pom properties
if artifactIDMatchesFilename(propertiesObj.ArtifactID, j.fileInfo.name, artifactsMap) {
pomProperties = propertiesObj
if pomProperties.ArtifactID == "" { // keep the first match, or overwrite if we find more specific entries
pomProperties = propertiesObj
}
if proj, exists := projects[parentPath]; exists {
parsedPom = proj
break
if parsedPom == nil { // keep the first matching artifact if we don't find an exact match or groupid + artfiact id match
pomProperties = propertiesObj // set this, as it may not be the first entry found
parsedPom = proj
}
// if artifact ID is the entire filename or BOTH artifactID and groupID are contained in the artifact, prefer this match
if strings.Contains(j.fileInfo.name, propertiesObj.GroupID) || j.fileInfo.name == propertiesObj.ArtifactID {
pomProperties = propertiesObj // this is an exact match, use it
parsedPom = proj
break
}
}
}
}
@@ -429,12 +444,13 @@ func (j *archiveParser) discoverMainPackageFromPomInfo(ctx context.Context) (gro
return group, name, version, parsedPom
}
func artifactIDMatchesFilename(artifactID, fileName string, artifactsMap map[string]bool) bool {
// artifactIDMatchesFilename returns true if one starts with the other
func artifactIDMatchesFilename(artifactID, fileName string, artifactsMap *strset.Set) bool {
if artifactID == "" || fileName == "" {
return false
}
// Ensure true is returned when filename matches the artifact ID, prevent random retrieval by checking prefix and suffix
if _, exists := artifactsMap[fileName]; exists {
if artifactsMap.Has(fileName) {
return artifactID == fileName
}
// Use fallback check with suffix and prefix if no POM properties file matches the exact artifact name
@@ -464,7 +480,7 @@ func (j *archiveParser) discoverPkgsFromAllMavenFiles(ctx context.Context, paren
return nil, err
}
for parentPath, propertiesObj := range properties {
for parentPath, propertiesObj := range sortedIter(properties) {
var parsedPom *parsedPomProject
if proj, exists := projects[parentPath]; exists {
parsedPom = proj
@@ -546,7 +562,7 @@ func discoverPkgsFromOpeners(ctx context.Context, location file.Location, opener
var pkgs []pkg.Package
var relationships []artifact.Relationship
for pathWithinArchive, archiveOpener := range openers {
for pathWithinArchive, archiveOpener := range sortedIter(openers) {
nestedPkgs, nestedRelationships, err := discoverPkgsFromOpener(ctx, location, pathWithinArchive, archiveOpener, cfg, parentPkg)
if err != nil {
log.WithFields("location", location.Path(), "error", err).Debug("unable to discover java packages from opener")
@@ -604,7 +620,7 @@ func pomPropertiesByParentPath(archivePath string, location file.Location, extra
}
propertiesByParentPath := make(map[string]pkg.JavaPomProperties)
for filePath, fileContents := range contentsOfMavenPropertiesFiles {
for filePath, fileContents := range sortedIter(contentsOfMavenPropertiesFiles) {
pomProperties, err := parsePomProperties(filePath, strings.NewReader(fileContents))
if err != nil {
log.WithFields("contents-path", filePath, "location", location.Path(), "error", err).Debug("failed to parse pom.properties")
@@ -633,7 +649,7 @@ func pomProjectByParentPath(archivePath string, location file.Location, extractP
}
projectByParentPath := make(map[string]*parsedPomProject)
for filePath, fileContents := range contentsOfMavenProjectFiles {
for filePath, fileContents := range sortedIter(contentsOfMavenProjectFiles) {
// TODO: when we support locations of paths within archives we should start passing the specific pom.xml location object instead of the top jar
pom, err := maven.ParsePomXML(strings.NewReader(fileContents))
if err != nil {
@@ -784,3 +800,15 @@ func updateParentPackage(p pkg.Package, parentPkg *pkg.Package) {
parentPkg.Metadata = parentMetadata
}
}
func sortedIter[K cmp.Ordered, V any](values map[K]V) iter.Seq2[K, V] {
return func(yield func(K, V) bool) {
keys := maps.Keys(values)
slices.Sort(keys)
for _, key := range keys {
if !yield(key, values[key]) {
return
}
}
}
}
@@ -1086,7 +1086,7 @@ func Test_artifactIDMatchesFilename(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, artifactIDMatchesFilename(tt.artifactID, tt.fileName, nil))
assert.Equal(t, tt.want, artifactIDMatchesFilename(tt.artifactID, tt.fileName, strset.New()))
})
}
}
@@ -1382,6 +1382,10 @@ func Test_deterministicMatchingPomProperties(t *testing.T) {
fixture: "multiple-matching-2.11.5",
expected: maven.NewID("org.multiple", "multiple-matching-1", "2.11.5"),
},
{
fixture: "org.multiple-thename",
expected: maven.NewID("org.multiple", "thename", "10.11.12"),
},
}
for _, test := range tests {
@@ -11,7 +11,7 @@ import (
"path"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/cpe"
@@ -36,16 +36,16 @@ func TestParseNativeImage(t *testing.T) {
for _, test := range tests {
t.Run(test.fixture, func(t *testing.T) {
f, err := os.Open("test-fixtures/java-builds/packages/" + test.fixture)
assert.NoError(t, err)
require.NoError(t, err)
readerCloser := io.NopCloser(f)
reader, err := unionreader.GetUnionReader(readerCloser)
assert.NoError(t, err)
require.NoError(t, err)
parsed := false
readers, err := unionreader.GetReaders(reader)
assert.NoError(t, err)
require.NoError(t, err)
for _, r := range readers {
ni, err := test.newFn(test.fixture, r)
assert.NoError(t, err)
require.NoError(t, err)
_, _, err = ni.fetchPkgs()
if err == nil {
t.Fatalf("should have failed to extract SBOM.")
@@ -228,11 +228,11 @@ func buildPackageMap(packages []pkg.Package) map[string]pkg.Package {
}
func verifyPackageFields(t *testing.T, expected, actual pkg.Package) {
assert.Equal(t, expected.Name, actual.Name)
assert.Equal(t, expected.Version, actual.Version)
assert.Equal(t, expected.FoundBy, actual.FoundBy)
assert.Equal(t, expected.PURL, actual.PURL)
assert.ElementsMatch(t, expected.CPEs, actual.CPEs)
require.Equal(t, expected.Name, actual.Name)
require.Equal(t, expected.Version, actual.Version)
require.Equal(t, expected.FoundBy, actual.FoundBy)
require.Equal(t, expected.PURL, actual.PURL)
require.ElementsMatch(t, expected.CPEs, actual.CPEs)
}
func verifyRelationships(t *testing.T, expected, actual []artifact.Relationship) {
@@ -260,8 +260,8 @@ func buildRelationshipMap(relationships []artifact.Relationship) map[string][]ar
}
func verifyRelationshipFields(t *testing.T, expected, actual []artifact.Relationship) {
assert.Equal(t, len(expected), len(actual))
require.Equal(t, len(expected), len(actual))
for i := range expected {
assert.Equal(t, expected[i].Type, actual[i].Type)
require.Equal(t, expected[i].Type, actual[i].Type)
}
}
+11 -5
View File
@@ -91,7 +91,7 @@ func parseJVMRelease(_ context.Context, resolver file.Resolver, _ *generic.Envir
// the reason we use the reference to get the real path is in cases where the file cataloger is involved
// (thus the real path is not available except for in the original file reference). This is important
// since the path is critical for distinguishing between different JVM vendors.
vendor, product := jvmPrimaryVendorProduct(ri.Implementor, string(reader.Reference().RealPath), ri.ImageType, hasJdk)
vendor, product := jvmPrimaryVendorProduct(ri, string(reader.Reference().RealPath), hasJdk)
p := pkg.Package{
Name: product,
@@ -163,11 +163,11 @@ func jvmPurl(ri pkg.JavaVMRelease, version, vendor, product string) string {
return pURL.ToString()
}
func jvmPrimaryVendorProduct(implementor, path, imageType string, hasJdk bool) (string, string) {
implementor = strings.ReplaceAll(strings.ToLower(implementor), " ", "")
func jvmPrimaryVendorProduct(ri *pkg.JavaVMRelease, path string, hasJdk bool) (string, string) {
implementor := strings.ReplaceAll(strings.ToLower(ri.Implementor), " ", "")
pickProduct := func() string {
if hasJdk || jvmProjectByType(imageType) == jdk {
if hasJdk || jvmProjectByType(ri.ImageType) == jdk {
return jdk
}
return jre
@@ -180,7 +180,13 @@ func jvmPrimaryVendorProduct(implementor, path, imageType string, hasJdk bool) (
case strings.Contains(implementor, "sun"):
return "sun", pickProduct()
case strings.Contains(implementor, "oracle") || strings.Contains(path, "oracle"):
case strings.Contains(implementor, "ibm") || strings.Contains(path, "/ibm"):
if hasJdk {
return "ibm", "java_sdk"
}
return "ibm", "java"
case strings.Contains(implementor, "oracle") || strings.Contains(path, "oracle") || strings.Contains(ri.BuildType, "commercial"):
return oracleVendor, pickProduct()
}
return oracleVendor, openJdkProduct
@@ -307,6 +307,7 @@ func TestJvmPrimaryVendorProduct(t *testing.T) {
tests := []struct {
name string
implementor string
buildType string
path string
imageType string
hasJdk bool
@@ -340,6 +341,25 @@ func TestJvmPrimaryVendorProduct(t *testing.T) {
expectedVendor: "oracle",
expectedProduct: "jre",
},
{
name: "Oracle commercial build type with JRE",
implementor: "",
buildType: "commercial",
path: "/usr/lib/jvm/jdk8/release",
imageType: "JRE",
hasJdk: false,
expectedVendor: "oracle",
expectedProduct: "jre",
},
{
name: "Oracle commercial build type with JDK",
implementor: "",
buildType: "commercial",
path: "/usr/lib/jvm/jdk8/release",
hasJdk: true,
expectedVendor: "oracle",
expectedProduct: "jdk",
},
{
name: "Oracle vendor with JDK in path",
implementor: "",
@@ -367,11 +387,29 @@ func TestJvmPrimaryVendorProduct(t *testing.T) {
expectedVendor: "oracle", // corretto upstream is oracle openjdk
expectedProduct: "openjdk",
},
{
name: "IBM JRE",
path: "/opt/ibm/java/release",
expectedVendor: "ibm",
expectedProduct: "java",
},
{
name: "IBM JDK",
path: "/opt/ibm/java/release",
hasJdk: true,
expectedVendor: "ibm",
expectedProduct: "java_sdk",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vendor, product := jvmPrimaryVendorProduct(tt.implementor, tt.path, tt.imageType, tt.hasJdk)
ri := pkg.JavaVMRelease{
Implementor: tt.implementor,
BuildType: tt.buildType,
ImageType: tt.imageType,
}
vendor, product := jvmPrimaryVendorProduct(&ri, tt.path, tt.hasJdk)
assert.Equal(t, tt.expectedVendor, vendor)
assert.Equal(t, tt.expectedProduct, product)
})
@@ -12,6 +12,7 @@ OPENSAML_CORE = opensaml-core-3.4.6
API_ALL_SOURCES = api-all-2.0.0-sources
SPRING_INSTRUMENTATION = spring-instrumentation-4.3.0-1.0
MULTIPLE_MATCHING = multiple-matching-2.11.5
ORG_MULTIPLE_THENAME = org.multiple-thename
.DEFAULT_GOAL := fixtures
@@ -48,7 +49,11 @@ $(CACHE_DIR)/$(MULTIPLE_MATCHING).jar:
mkdir -p $(CACHE_DIR)
cd $(MULTIPLE_MATCHING) && zip -r $(CACHE_PATH)/$(MULTIPLE_MATCHING).jar .
# Jenkins plugins typically do not have the version included in the archive name,
$(CACHE_DIR)/$(ORG_MULTIPLE_THENAME).jar:
mkdir -p $(CACHE_DIR)
cd $(ORG_MULTIPLE_THENAME) && zip -r $(CACHE_PATH)/$(ORG_MULTIPLE_THENAME).jar .
# Jenkins plugins typically do not have the version included in the archive name,
# so it is important to not include it in the generated test fixture
$(CACHE_DIR)/gradle.hpi:
mkdir -p $(CACHE_DIR)
@@ -0,0 +1,2 @@
Manifest-Version: 1.0
Created-By: Multi
@@ -0,0 +1,3 @@
version=10.11.12
groupId=com.multiple
artifactId=thename
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.multiple</groupId>
<artifactId>thename</artifactId>
<version>10.11.12</version>
</project>
@@ -0,0 +1,3 @@
version=10.11.12
groupId=org.multiple
artifactId=thename
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.multiple</groupId>
<artifactId>thename</artifactId>
<version>10.11.12</version>
</project>
@@ -219,7 +219,7 @@ func (p interpreterCataloger) getClassifier(realPath string) (string, *binutils.
return name, &binutils.Classifier{
Class: fmt.Sprintf("php-ext-%s-binary", name),
EvidenceMatcher: binutils.FileContentsVersionMatcher(match, p.name),
EvidenceMatcher: binutils.FileContentsVersionMatcher(p.name, match),
Package: name,
PURL: packageurl.PackageURL{
Type: packageurl.TypeGeneric,
@@ -4,14 +4,27 @@ import (
"testing"
"github.com/anchore/syft/syft/internal/packagemetadata"
"github.com/anchore/syft/syft/internal/sourcemetadata"
)
type PackageMetadataCompletionTester struct {
*packagemetadata.CompletionTester
}
type SourceMetadataCompletionTester struct {
*sourcemetadata.CompletionTester
}
func NewPackageMetadataCompletionTester(t testing.TB, ignore ...any) *PackageMetadataCompletionTester {
t.Helper()
return &PackageMetadataCompletionTester{
CompletionTester: packagemetadata.NewCompletionTester(t, ignore...),
}
}
func NewSourceMetadataCompletionTester(t testing.TB, ignore ...any) *SourceMetadataCompletionTester {
t.Helper()
return &SourceMetadataCompletionTester{
CompletionTester: sourcemetadata.NewCompletionTester(t, ignore...),
}
}