mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
Merge branch 'main' into 4184-gguf-parser
* main: chore(deps): update tools to latest versions (#4302) chore(deps): bump github.com/github/go-spdx/v2 from 2.3.3 to 2.3.4 (#4301) chore(deps): bump github/codeql-action from 4.30.8 to 4.30.9 (#4299) support universal (fat) mach-o binary files (#4278) chore(deps): bump sigstore/cosign-installer from 3.10.0 to 4.0.0 (#4296) chore(deps): bump anchore/sbom-action from 0.20.7 to 0.20.8 (#4297) convert posix path back to windows (#4285) Remove duplicate image source providers (#4289) chore(deps): bump anchore/sbom-action from 0.20.6 to 0.20.7 (#4293) feat: add option to fetch remote licenses for pnpm-lock.yaml files (#4286) Add PDM parser (#4234) chore(deps): update tools to latest versions (#4291) fix: panic during java archive maven resolution (#4290) Extract zip archive with multiple entries (#4283) chore: update to use old configuration on new cosign (#4287) chore(deps): update anchore dependencies (#4282) chore(deps): bump github.com/mholt/archives from 0.1.3 to 0.1.5 (#4280) add docs to configs (#4281)
This commit is contained in:
commit
3326ae44fa
@ -58,7 +58,7 @@ tools:
|
|||||||
# used to release all artifacts
|
# used to release all artifacts
|
||||||
- name: goreleaser
|
- name: goreleaser
|
||||||
version:
|
version:
|
||||||
want: v2.12.5
|
want: v2.12.6
|
||||||
method: github-release
|
method: github-release
|
||||||
with:
|
with:
|
||||||
repo: goreleaser/goreleaser
|
repo: goreleaser/goreleaser
|
||||||
@ -98,7 +98,7 @@ tools:
|
|||||||
# used for triggering a release
|
# used for triggering a release
|
||||||
- name: gh
|
- name: gh
|
||||||
version:
|
version:
|
||||||
want: v2.81.0
|
want: v2.82.1
|
||||||
method: github-release
|
method: github-release
|
||||||
with:
|
with:
|
||||||
repo: cli/cli
|
repo: cli/cli
|
||||||
|
|||||||
@ -9,6 +9,9 @@ permit:
|
|||||||
- Unlicense
|
- Unlicense
|
||||||
|
|
||||||
ignore-packages:
|
ignore-packages:
|
||||||
|
# https://github.com/sorairolake/lzip-go/blob/34a2615d2abf740175c6b0a835baa08364e09430/go.sum.license#L3
|
||||||
|
# has `SPDX-License-Identifier: Apache-2.0 OR MIT`, both of which are acceptable
|
||||||
|
- github.com/sorairolake/lzip-go
|
||||||
# packageurl-go is released under the MIT license located in the root of the repo at /mit.LICENSE
|
# packageurl-go is released under the MIT license located in the root of the repo at /mit.LICENSE
|
||||||
- github.com/anchore/packageurl-go
|
- github.com/anchore/packageurl-go
|
||||||
|
|
||||||
|
|||||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@ -47,7 +47,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 #v3.29.5
|
uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 #v3.29.5
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# 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).
|
# 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)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@f443b600d91635bebf5b0d9ebc620189c0d6fba5 #v3.29.5
|
uses: github/codeql-action/autobuild@16140ae1a102900babc80a33c44059580f687047 #v3.29.5
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@ -72,4 +72,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 #v3.29.5
|
uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 #v3.29.5
|
||||||
|
|||||||
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@ -161,7 +161,7 @@ jobs:
|
|||||||
# for updating brew formula in anchore/homebrew-syft
|
# for updating brew formula in anchore/homebrew-syft
|
||||||
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
|
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
|
||||||
|
|
||||||
- uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b #v0.20.6
|
- uses: anchore/sbom-action@aa0e114b2e19480f157109b9922bda359bd98b90 #v0.20.8
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
file: go.mod
|
file: go.mod
|
||||||
|
|||||||
2
.github/workflows/validations.yaml
vendored
2
.github/workflows/validations.yaml
vendored
@ -210,7 +210,7 @@ jobs:
|
|||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Install Cosign
|
- name: Install Cosign
|
||||||
uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
|
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
|
||||||
|
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
|
||||||
with:
|
with:
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
go.work
|
go.work
|
||||||
go.work.sum
|
go.work.sum
|
||||||
.tool-versions
|
.tool-versions
|
||||||
|
.python-version
|
||||||
|
|
||||||
# app configuration
|
# app configuration
|
||||||
/.syft.yaml
|
/.syft.yaml
|
||||||
@ -16,6 +17,8 @@ bin/
|
|||||||
/snapshot
|
/snapshot
|
||||||
/.tool
|
/.tool
|
||||||
/.task
|
/.task
|
||||||
|
/generate
|
||||||
|
/specs
|
||||||
|
|
||||||
# changelog generation
|
# changelog generation
|
||||||
CHANGELOG.md
|
CHANGELOG.md
|
||||||
|
|||||||
@ -337,6 +337,7 @@ signs:
|
|||||||
certificate: "${artifact}.pem"
|
certificate: "${artifact}.pem"
|
||||||
args:
|
args:
|
||||||
- "sign-blob"
|
- "sign-blob"
|
||||||
|
- "--use-signing-config=false"
|
||||||
- "--oidc-issuer=https://token.actions.githubusercontent.com"
|
- "--oidc-issuer=https://token.actions.githubusercontent.com"
|
||||||
- "--output-certificate=${certificate}"
|
- "--output-certificate=${certificate}"
|
||||||
- "--output-signature=${signature}"
|
- "--output-signature=${signature}"
|
||||||
|
|||||||
24
go.mod
24
go.mod
@ -15,7 +15,7 @@ require (
|
|||||||
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9
|
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9
|
||||||
github.com/anchore/clio v0.0.0-20250319180342-2cfe4b0cb716
|
github.com/anchore/clio v0.0.0-20250319180342-2cfe4b0cb716
|
||||||
github.com/anchore/fangs v0.0.0-20250319222917-446a1e748ec2
|
github.com/anchore/fangs v0.0.0-20250319222917-446a1e748ec2
|
||||||
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537
|
github.com/anchore/go-collections v0.0.0-20251016125210-a3c352120e8c
|
||||||
github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d
|
github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d
|
||||||
github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722
|
github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722
|
||||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
||||||
@ -24,7 +24,7 @@ require (
|
|||||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
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/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115
|
||||||
github.com/anchore/stereoscope v0.1.10
|
github.com/anchore/stereoscope v0.1.11
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
||||||
github.com/aquasecurity/go-pep440-version v0.0.1
|
github.com/aquasecurity/go-pep440-version v0.0.1
|
||||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
|
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
|
||||||
@ -40,7 +40,7 @@ require (
|
|||||||
github.com/dustin/go-humanize v1.0.1
|
github.com/dustin/go-humanize v1.0.1
|
||||||
github.com/elliotchance/phpserialize v1.4.0
|
github.com/elliotchance/phpserialize v1.4.0
|
||||||
github.com/facebookincubator/nvdtools v0.1.5
|
github.com/facebookincubator/nvdtools v0.1.5
|
||||||
github.com/github/go-spdx/v2 v2.3.3
|
github.com/github/go-spdx/v2 v2.3.4
|
||||||
github.com/gkampitakis/go-snaps v0.5.15
|
github.com/gkampitakis/go-snaps v0.5.15
|
||||||
github.com/go-git/go-billy/v5 v5.6.2
|
github.com/go-git/go-billy/v5 v5.6.2
|
||||||
github.com/go-git/go-git/v5 v5.16.3
|
github.com/go-git/go-git/v5 v5.16.3
|
||||||
@ -62,7 +62,7 @@ require (
|
|||||||
github.com/jinzhu/copier v0.4.0
|
github.com/jinzhu/copier v0.4.0
|
||||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
|
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
|
||||||
github.com/magiconair/properties v1.8.10
|
github.com/magiconair/properties v1.8.10
|
||||||
github.com/mholt/archives v0.1.3
|
github.com/mholt/archives v0.1.5
|
||||||
github.com/moby/sys/mountinfo v0.7.2
|
github.com/moby/sys/mountinfo v0.7.2
|
||||||
github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1
|
github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1
|
||||||
github.com/olekukonko/tablewriter v1.0.9
|
github.com/olekukonko/tablewriter v1.0.9
|
||||||
@ -110,11 +110,11 @@ require (
|
|||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/Microsoft/hcsshim v0.11.7 // indirect
|
github.com/Microsoft/hcsshim v0.11.7 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
||||||
github.com/STARRY-S/zip v0.2.1 // indirect
|
github.com/STARRY-S/zip v0.2.3 // indirect
|
||||||
github.com/agext/levenshtein v1.2.1 // indirect; indirectt
|
github.com/agext/levenshtein v1.2.1 // indirect; indirectt
|
||||||
github.com/anchore/go-lzo v0.1.0 // indirect
|
github.com/anchore/go-lzo v0.1.0 // indirect
|
||||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||||
github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 // indirect
|
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||||
github.com/aquasecurity/go-version v0.0.1 // indirect
|
github.com/aquasecurity/go-version v0.0.1 // indirect
|
||||||
github.com/atotto/clipboard v0.1.4 // indirect
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
@ -122,7 +122,7 @@ require (
|
|||||||
github.com/becheran/wildmatch-go v1.0.0 // indirect
|
github.com/becheran/wildmatch-go v1.0.0 // indirect
|
||||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||||
github.com/bodgit/plumbing v1.3.0 // indirect
|
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||||
github.com/bodgit/sevenzip v1.6.0 // indirect
|
github.com/bodgit/sevenzip v1.6.1 // indirect
|
||||||
github.com/bodgit/windows v1.0.1 // indirect
|
github.com/bodgit/windows v1.0.1 // indirect
|
||||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||||
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
||||||
@ -144,9 +144,9 @@ require (
|
|||||||
github.com/containerd/typeurl/v2 v2.2.0 // indirect
|
github.com/containerd/typeurl/v2 v2.2.0 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/docker/cli v28.4.0+incompatible // indirect
|
github.com/docker/cli v28.5.1+incompatible // indirect
|
||||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
github.com/docker/docker v28.4.0+incompatible // indirect
|
github.com/docker/docker v28.5.1+incompatible // indirect
|
||||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||||
github.com/docker/go-connections v0.6.0 // indirect
|
github.com/docker/go-connections v0.6.0 // indirect
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||||
@ -194,7 +194,7 @@ require (
|
|||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
github.com/mikelolasagasti/xz v1.0.1 // indirect
|
github.com/mikelolasagasti/xz v1.0.1 // indirect
|
||||||
github.com/minio/minlz v1.0.0 // indirect
|
github.com/minio/minlz v1.0.1 // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
@ -210,7 +210,7 @@ require (
|
|||||||
github.com/muesli/termenv v0.16.0 // indirect
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||||
github.com/nwaples/rardecode/v2 v2.1.0 // indirect
|
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
|
||||||
github.com/olekukonko/errors v1.1.0 // indirect
|
github.com/olekukonko/errors v1.1.0 // indirect
|
||||||
github.com/olekukonko/ll v0.0.9 // indirect
|
github.com/olekukonko/ll v0.0.9 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
@ -232,7 +232,7 @@ require (
|
|||||||
github.com/shopspring/decimal v1.4.0 // indirect
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
|
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
|
||||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||||
github.com/sorairolake/lzip-go v0.3.5 // indirect
|
github.com/sorairolake/lzip-go v0.3.8 // indirect
|
||||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
github.com/spf13/cast v1.7.1 // indirect
|
github.com/spf13/cast v1.7.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.9 // indirect
|
github.com/spf13/pflag v1.0.9 // indirect
|
||||||
|
|||||||
48
go.sum
48
go.sum
@ -94,8 +94,8 @@ github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8
|
|||||||
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
||||||
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
||||||
github.com/STARRY-S/zip v0.2.1 h1:pWBd4tuSGm3wtpoqRZZ2EAwOmcHK6XFf7bU9qcJXyFg=
|
github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4=
|
||||||
github.com/STARRY-S/zip v0.2.1/go.mod h1:xNvshLODWtC4EJ702g7cTYn13G53o1+X9BWnPFpcWV4=
|
github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk=
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||||
github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
|
github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
|
||||||
@ -116,8 +116,8 @@ github.com/anchore/clio v0.0.0-20250319180342-2cfe4b0cb716 h1:2sIdYJlQESEnyk3Y0W
|
|||||||
github.com/anchore/clio v0.0.0-20250319180342-2cfe4b0cb716/go.mod h1:Utb9i4kwiCWvqAIxZaJeMIXFO9uOgQXlvH2BfbfO/zI=
|
github.com/anchore/clio v0.0.0-20250319180342-2cfe4b0cb716/go.mod h1:Utb9i4kwiCWvqAIxZaJeMIXFO9uOgQXlvH2BfbfO/zI=
|
||||||
github.com/anchore/fangs v0.0.0-20250319222917-446a1e748ec2 h1:GC2QaO0YsmjpsZ4rtVKv9DnproIxqqn+qkskpc+i8MA=
|
github.com/anchore/fangs v0.0.0-20250319222917-446a1e748ec2 h1:GC2QaO0YsmjpsZ4rtVKv9DnproIxqqn+qkskpc+i8MA=
|
||||||
github.com/anchore/fangs v0.0.0-20250319222917-446a1e748ec2/go.mod h1:XUbUECwVKuD3qYRUj+QZIOHjyyXua2gFmVjKA40iHXA=
|
github.com/anchore/fangs v0.0.0-20250319222917-446a1e748ec2/go.mod h1:XUbUECwVKuD3qYRUj+QZIOHjyyXua2gFmVjKA40iHXA=
|
||||||
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537 h1:GjNGuwK5jWjJMyVppBjYS54eOiiSNv4Ba869k4wh72Q=
|
github.com/anchore/go-collections v0.0.0-20251016125210-a3c352120e8c h1:eoJXyC0n7DZ4YvySG/ETdYkTar2Due7eH+UmLK6FbrA=
|
||||||
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537/go.mod h1:1aiktV46ATCkuVg0O573ZrH56BUawTECPETbZyBcqT8=
|
github.com/anchore/go-collections v0.0.0-20251016125210-a3c352120e8c/go.mod h1:1aiktV46ATCkuVg0O573ZrH56BUawTECPETbZyBcqT8=
|
||||||
github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d h1:gT69osH9AsdpOfqxbRwtxcNnSZ1zg4aKy2BevO3ZBdc=
|
github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d h1:gT69osH9AsdpOfqxbRwtxcNnSZ1zg4aKy2BevO3ZBdc=
|
||||||
github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d/go.mod h1:PhSnuFYknwPZkOWKB1jXBNToChBA+l0FjwOxtViIc50=
|
github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d/go.mod h1:PhSnuFYknwPZkOWKB1jXBNToChBA+l0FjwOxtViIc50=
|
||||||
github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722 h1:2SqmFgE7h+Ql4VyBzhjLkRF/3gDrcpUBj8LjvvO6OOM=
|
github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722 h1:2SqmFgE7h+Ql4VyBzhjLkRF/3gDrcpUBj8LjvvO6OOM=
|
||||||
@ -138,11 +138,11 @@ 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/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 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/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI=
|
||||||
github.com/anchore/stereoscope v0.1.10 h1:BogafIMaW/L1lOUoVS96Hu1jTSP2JktxIayVqcxvcBI=
|
github.com/anchore/stereoscope v0.1.11 h1:YP/XUNcJyMbOOPAWPkeZNCVlKKTRO2cnBTEeUW6I40Y=
|
||||||
github.com/anchore/stereoscope v0.1.10/go.mod h1:RWFAkQE8tp8yyaf4V83Kq1bO6hX3bzi8gpLCcKgZLIk=
|
github.com/anchore/stereoscope v0.1.11/go.mod h1:G3PZlzPbxFhylj9pQwtqfVPaahuWmy/UCtv5FTIIMvg=
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 h1:8PmGpDEZl9yDpcdEr6Odf23feCxK3LNUNMxjXg41pZQ=
|
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||||
github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
@ -217,8 +217,8 @@ github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/
|
|||||||
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
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 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
|
||||||
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
|
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
|
||||||
github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A=
|
github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4=
|
||||||
github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc=
|
github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8=
|
||||||
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
|
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
|
||||||
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
||||||
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
|
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
|
||||||
@ -322,12 +322,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/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 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||||
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||||
github.com/docker/cli v28.4.0+incompatible h1:RBcf3Kjw2pMtwui5V0DIMdyeab8glEw5QY0UUU4C9kY=
|
github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
|
||||||
github.com/docker/cli v28.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v28.5.1+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 h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v28.4.0+incompatible h1:KVC7bz5zJY/4AZe/78BIvCnPsLaC9T/zh72xnlrTTOk=
|
github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
|
||||||
github.com/docker/docker v28.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v28.5.1+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 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
||||||
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
||||||
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||||
@ -385,8 +385,8 @@ github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8
|
|||||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/github/go-spdx/v2 v2.3.3 h1:QI7evnHWEfWkT54eJwkoV/f3a0xD3gLlnVmT5wQG6LE=
|
github.com/github/go-spdx/v2 v2.3.4 h1:6VNAsYWvQge+SOeoubTlH81MY21d5uekXNIRGfXMNXo=
|
||||||
github.com/github/go-spdx/v2 v2.3.3/go.mod h1:2ZxKsOhvBp+OYBDlsGnUMcchLeo2mrpEBn2L1C+U3IQ=
|
github.com/github/go-spdx/v2 v2.3.4/go.mod h1:7LYNCshU2Gj17qZ0heJ5CQUKWWmpd98K7o93K8fJSMk=
|
||||||
github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=
|
github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=
|
||||||
github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
|
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 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
|
||||||
@ -686,15 +686,15 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
|
|||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
github.com/mholt/archives v0.1.3 h1:aEAaOtNra78G+TvV5ohmXrJOAzf++dIlYeDW3N9q458=
|
github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ=
|
||||||
github.com/mholt/archives v0.1.3/go.mod h1:LUCGp++/IbV/I0Xq4SzcIR6uwgeh2yjnQWamjRQfLTU=
|
github.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0=
|
github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0=
|
||||||
github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc=
|
github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc=
|
||||||
github.com/minio/minlz v1.0.0 h1:Kj7aJZ1//LlTP1DM8Jm7lNKvvJS2m74gyyXXn3+uJWQ=
|
github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A=
|
||||||
github.com/minio/minlz v1.0.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
|
github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
|
||||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||||
@ -750,8 +750,8 @@ github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1a
|
|||||||
github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8=
|
github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8=
|
||||||
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
||||||
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
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.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A=
|
||||||
github.com/nwaples/rardecode/v2 v2.1.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
||||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
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 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
||||||
@ -860,8 +860,8 @@ github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnB
|
|||||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||||
github.com/smallnest/ringbuffer v0.0.0-20241116012123-461381446e3d h1:3VwvTjiRPA7cqtgOWddEL+JrcijMlXUmj99c/6YyZoY=
|
github.com/smallnest/ringbuffer v0.0.0-20241116012123-461381446e3d h1:3VwvTjiRPA7cqtgOWddEL+JrcijMlXUmj99c/6YyZoY=
|
||||||
github.com/smallnest/ringbuffer v0.0.0-20241116012123-461381446e3d/go.mod h1:tAG61zBM1DYRaGIPloumExGvScf08oHuo0kFoOqdbT0=
|
github.com/smallnest/ringbuffer v0.0.0-20241116012123-461381446e3d/go.mod h1:tAG61zBM1DYRaGIPloumExGvScf08oHuo0kFoOqdbT0=
|
||||||
github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu0Cwg=
|
github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik=
|
||||||
github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk=
|
github.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU=
|
||||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
|||||||
@ -52,6 +52,7 @@ func AllTypes() []any {
|
|||||||
pkg.PhpPeclEntry{},
|
pkg.PhpPeclEntry{},
|
||||||
pkg.PortageEntry{},
|
pkg.PortageEntry{},
|
||||||
pkg.PythonPackage{},
|
pkg.PythonPackage{},
|
||||||
|
pkg.PythonPdmLockEntry{},
|
||||||
pkg.PythonPipfileLockEntry{},
|
pkg.PythonPipfileLockEntry{},
|
||||||
pkg.PythonPoetryLockEntry{},
|
pkg.PythonPoetryLockEntry{},
|
||||||
pkg.PythonRequirementsEntry{},
|
pkg.PythonRequirementsEntry{},
|
||||||
|
|||||||
@ -102,6 +102,7 @@ var jsonTypes = makeJSONTypes(
|
|||||||
jsonNames(pkg.PhpPearEntry{}, "php-pear-entry"),
|
jsonNames(pkg.PhpPearEntry{}, "php-pear-entry"),
|
||||||
jsonNames(pkg.PortageEntry{}, "portage-db-entry", "PortageMetadata"),
|
jsonNames(pkg.PortageEntry{}, "portage-db-entry", "PortageMetadata"),
|
||||||
jsonNames(pkg.PythonPackage{}, "python-package", "PythonPackageMetadata"),
|
jsonNames(pkg.PythonPackage{}, "python-package", "PythonPackageMetadata"),
|
||||||
|
jsonNames(pkg.PythonPdmLockEntry{}, "python-pdm-lock-entry"),
|
||||||
jsonNames(pkg.PythonPipfileLockEntry{}, "python-pipfile-lock-entry", "PythonPipfileLockMetadata"),
|
jsonNames(pkg.PythonPipfileLockEntry{}, "python-pipfile-lock-entry", "PythonPipfileLockMetadata"),
|
||||||
jsonNames(pkg.PythonPoetryLockEntry{}, "python-poetry-lock-entry", "PythonPoetryLockMetadata"),
|
jsonNames(pkg.PythonPoetryLockEntry{}, "python-poetry-lock-entry", "PythonPoetryLockMetadata"),
|
||||||
jsonNames(pkg.PythonRequirementsEntry{}, "python-pip-requirements-entry", "PythonRequirementsMetadata"),
|
jsonNames(pkg.PythonRequirementsEntry{}, "python-pip-requirements-entry", "PythonRequirementsMetadata"),
|
||||||
|
|||||||
4011
schema/json/schema-16.0.41.json
Normal file
4011
schema/json/schema-16.0.41.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -2616,6 +2616,9 @@
|
|||||||
{
|
{
|
||||||
"$ref": "#/$defs/PythonPackage"
|
"$ref": "#/$defs/PythonPackage"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/PythonPdmLockEntry"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/$defs/PythonPipRequirementsEntry"
|
"$ref": "#/$defs/PythonPipRequirementsEntry"
|
||||||
},
|
},
|
||||||
@ -3198,6 +3201,35 @@
|
|||||||
],
|
],
|
||||||
"description": "PythonPackage represents all captured data for a python egg or wheel package (specifically as outlined in the PyPA core metadata specification https://packaging.python.org/en/latest/specifications/core-metadata/)."
|
"description": "PythonPackage represents all captured data for a python egg or wheel package (specifically as outlined in the PyPA core metadata specification https://packaging.python.org/en/latest/specifications/core-metadata/)."
|
||||||
},
|
},
|
||||||
|
"PythonPdmLockEntry": {
|
||||||
|
"properties": {
|
||||||
|
"summary": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Summary provides a description of the package"
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/PythonFileRecord"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"description": "Files are the package files with their paths and hash digests"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"description": "Dependencies are the dependency specifications, without environment qualifiers"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"summary",
|
||||||
|
"files",
|
||||||
|
"dependencies"
|
||||||
|
],
|
||||||
|
"description": "PythonPdmLockEntry represents a single package entry within a pdm.lock file."
|
||||||
|
},
|
||||||
"PythonPipRequirementsEntry": {
|
"PythonPipRequirementsEntry": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package executable
|
|||||||
import (
|
import (
|
||||||
"debug/macho"
|
"debug/macho"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal"
|
||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/internal/unionreader"
|
"github.com/anchore/syft/syft/internal/unionreader"
|
||||||
)
|
)
|
||||||
@ -19,20 +20,38 @@ const (
|
|||||||
func findMachoFeatures(data *file.Executable, reader unionreader.UnionReader) error {
|
func findMachoFeatures(data *file.Executable, reader unionreader.UnionReader) error {
|
||||||
// TODO: support security features
|
// TODO: support security features
|
||||||
|
|
||||||
// TODO: support multi-architecture binaries
|
// a universal binary may have multiple architectures, so we need to check each one
|
||||||
f, err := macho.NewFile(reader)
|
readers, err := unionreader.GetReaders(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
libs, err := f.ImportedLibraries()
|
var libs []string
|
||||||
if err != nil {
|
for _, r := range readers {
|
||||||
return err
|
f, err := macho.NewFile(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rLibs, err := f.ImportedLibraries()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
libs = append(libs, rLibs...)
|
||||||
|
|
||||||
|
// TODO handle only some having entrypoints/exports? If that is even practical
|
||||||
|
// only check for entrypoint if we don't already have one
|
||||||
|
if !data.HasEntrypoint {
|
||||||
|
data.HasEntrypoint = machoHasEntrypoint(f)
|
||||||
|
}
|
||||||
|
// only check for exports if we don't already have them
|
||||||
|
if !data.HasExports {
|
||||||
|
data.HasExports = machoHasExports(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.ImportedLibraries = libs
|
// de-duplicate libraries
|
||||||
data.HasEntrypoint = machoHasEntrypoint(f)
|
data.ImportedLibraries = internal.NewSet(libs...).ToSlice()
|
||||||
data.HasExports = machoHasExports(f)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/internal/unionreader"
|
"github.com/anchore/syft/syft/internal/unionreader"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -83,3 +84,39 @@ func Test_machoHasExports(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_machoUniversal(t *testing.T) {
|
||||||
|
readerForFixture := func(t *testing.T, fixture string) unionreader.UnionReader {
|
||||||
|
t.Helper()
|
||||||
|
f, err := os.Open(filepath.Join("test-fixtures/shared-info", fixture))
|
||||||
|
require.NoError(t, err)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fixture string
|
||||||
|
want file.Executable
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "universal lib",
|
||||||
|
fixture: "bin/libhello_universal.dylib",
|
||||||
|
want: file.Executable{HasExports: true, HasEntrypoint: false},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "universal application",
|
||||||
|
fixture: "bin/hello_mac_universal",
|
||||||
|
want: file.Executable{HasExports: false, HasEntrypoint: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var data file.Executable
|
||||||
|
err := findMachoFeatures(&data, readerForFixture(t, tt.fixture))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want.HasEntrypoint, data.HasEntrypoint)
|
||||||
|
assert.Equal(t, tt.want.HasExports, data.HasExports)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
BIN=../../bin
|
BIN=../../bin
|
||||||
|
|
||||||
all: $(BIN)/hello_linux $(BIN)/hello.exe $(BIN)/hello_mac
|
all: $(BIN)/hello_linux $(BIN)/hello.exe $(BIN)/hello_mac $(BIN)/hello_mac_universal
|
||||||
|
|
||||||
linux: $(BIN)/libhello.so
|
linux: $(BIN)/libhello.so
|
||||||
|
|
||||||
windows: $(BIN)/libhello.dll
|
windows: $(BIN)/libhello.dll
|
||||||
|
|
||||||
mac: $(BIN)/libhello.dylib
|
mac: $(BIN)/libhello.dylib $(BIN)/hello_mac_universal
|
||||||
|
|
||||||
$(BIN)/hello_linux:
|
$(BIN)/hello_linux:
|
||||||
gcc hello.c -o $(BIN)/hello_linux
|
gcc hello.c -o $(BIN)/hello_linux
|
||||||
@ -19,5 +19,8 @@ $(BIN)/hello.exe:
|
|||||||
$(BIN)/hello_mac:
|
$(BIN)/hello_mac:
|
||||||
o64-clang hello.c -o $(BIN)/hello_mac
|
o64-clang hello.c -o $(BIN)/hello_mac
|
||||||
|
|
||||||
|
$(BIN)/hello_mac_universal:
|
||||||
|
o64-clang -arch arm64 -arch x86_64 hello.c -o $(BIN)/hello_mac_universal
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(BIN)/hello_linux $(BIN)/hello.exe $(BIN)/hello_mac
|
rm -f $(BIN)/hello_linux $(BIN)/hello.exe $(BIN)/hello_mac $(BIN)/hello_mac_universal
|
||||||
|
|||||||
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
BIN=../../bin
|
BIN=../../bin
|
||||||
|
|
||||||
all: $(BIN)/libhello.so $(BIN)/libhello.dll $(BIN)/libhello.dylib
|
all: $(BIN)/libhello.so $(BIN)/libhello.dll $(BIN)/libhello.dylib $(BIN)/libhello_universal.dylib
|
||||||
|
|
||||||
linux: $(BIN)/libhello.so
|
linux: $(BIN)/libhello.so
|
||||||
|
|
||||||
windows: $(BIN)/libhello.dll
|
windows: $(BIN)/libhello.dll
|
||||||
|
|
||||||
mac: $(BIN)/libhello.dylib
|
mac: $(BIN)/libhello.dylib $(BIN)/libhello_universal.dylib
|
||||||
|
|
||||||
$(BIN)/libhello.so:
|
$(BIN)/libhello.so:
|
||||||
gcc -shared -fPIC -o $(BIN)/libhello.so hello.c
|
gcc -shared -fPIC -o $(BIN)/libhello.so hello.c
|
||||||
@ -19,5 +19,8 @@ $(BIN)/libhello.dll:
|
|||||||
$(BIN)/libhello.dylib:
|
$(BIN)/libhello.dylib:
|
||||||
o64-clang -dynamiclib -o $(BIN)/libhello.dylib hello.c
|
o64-clang -dynamiclib -o $(BIN)/libhello.dylib hello.c
|
||||||
|
|
||||||
|
$(BIN)/libhello_universal.dylib:
|
||||||
|
o64-clang -dynamiclib -arch arm64 -arch x86_64 hello.c -o $(BIN)/libhello_universal.dylib
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(BIN)/libhello.so $(BIN)/hello.dll $(BIN)/libhello.dylib $(BIN)/libhello.a
|
rm -f $(BIN)/libhello.so $(BIN)/hello.dll $(BIN)/libhello.dylib $(BIN)/libhello.a $(BIN)/libhello_universal.dylib
|
||||||
|
|||||||
@ -42,6 +42,7 @@ func Test_OriginatorSupplier(t *testing.T) {
|
|||||||
pkg.PhpPeclEntry{},
|
pkg.PhpPeclEntry{},
|
||||||
pkg.PortageEntry{},
|
pkg.PortageEntry{},
|
||||||
pkg.PythonPipfileLockEntry{},
|
pkg.PythonPipfileLockEntry{},
|
||||||
|
pkg.PythonPdmLockEntry{},
|
||||||
pkg.PythonRequirementsEntry{},
|
pkg.PythonRequirementsEntry{},
|
||||||
pkg.PythonPoetryLockEntry{},
|
pkg.PythonPoetryLockEntry{},
|
||||||
pkg.PythonUvLockEntry{},
|
pkg.PythonUvLockEntry{},
|
||||||
@ -343,6 +344,25 @@ func Test_OriginatorSupplier(t *testing.T) {
|
|||||||
originator: "Person: auth (auth@auth.gov)",
|
originator: "Person: auth (auth@auth.gov)",
|
||||||
supplier: "Person: auth (auth@auth.gov)",
|
supplier: "Person: auth (auth@auth.gov)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "from python PDM lock",
|
||||||
|
input: pkg.Package{
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Summary: "A test package",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
originator: "",
|
||||||
|
supplier: "",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "from r -- maintainer > author",
|
name: "from r -- maintainer > author",
|
||||||
input: pkg.Package{
|
input: pkg.Package{
|
||||||
|
|||||||
37
syft/get_source_config_test.go
Normal file
37
syft/get_source_config_test.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package syft
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/stereoscope"
|
||||||
|
"github.com/anchore/syft/syft/source/sourceproviders"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetProviders_DefaultImagePullSource(t *testing.T) {
|
||||||
|
userInput := ""
|
||||||
|
cfg := &GetSourceConfig{DefaultImagePullSource: stereoscope.RegistryTag}
|
||||||
|
allSourceProviders := sourceproviders.All(userInput, cfg.SourceProviderConfig)
|
||||||
|
|
||||||
|
providers, err := cfg.getProviders(userInput)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error for DefaultImagePullSource parameter, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(providers) != len(allSourceProviders) {
|
||||||
|
t.Errorf("Expected %d providers, got %d", len(allSourceProviders), len(providers))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetProviders_Sources(t *testing.T) {
|
||||||
|
userInput := ""
|
||||||
|
cfg := &GetSourceConfig{Sources: []string{stereoscope.RegistryTag}}
|
||||||
|
|
||||||
|
providers, err := cfg.getProviders(userInput)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error for Sources parameter, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(providers) != 1 {
|
||||||
|
t.Errorf("Expected 1 providers, got %d", len(providers))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -322,7 +322,7 @@ func (r directoryIndexer) addDirectoryToIndex(p string, info os.FileInfo) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := file.NewMetadataFromPath(p, info)
|
metadata := NewMetadataFromPath(p, info)
|
||||||
r.index.Add(*ref, metadata)
|
r.index.Add(*ref, metadata)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -334,7 +334,7 @@ func (r directoryIndexer) addFileToIndex(p string, info os.FileInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := file.NewMetadataFromPath(p, info)
|
metadata := NewMetadataFromPath(p, info)
|
||||||
r.index.Add(*ref, metadata)
|
r.index.Add(*ref, metadata)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -416,7 +416,7 @@ func (r directoryIndexer) addSymlinkToIndex(p string, info os.FileInfo) (string,
|
|||||||
targetAbsPath = filepath.Clean(filepath.Join(path.Dir(p), linkTarget))
|
targetAbsPath = filepath.Clean(filepath.Join(path.Dir(p), linkTarget))
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := file.NewMetadataFromPath(p, info)
|
metadata := NewMetadataFromPath(p, info)
|
||||||
metadata.LinkDestination = linkTarget
|
metadata.LinkDestination = linkTarget
|
||||||
r.index.Add(*ref, metadata)
|
r.index.Add(*ref, metadata)
|
||||||
|
|
||||||
|
|||||||
@ -173,7 +173,7 @@ func (r *fileIndexer) addDirectoryToIndex(path string, info os.FileInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := file.NewMetadataFromPath(path, info)
|
metadata := NewMetadataFromPath(path, info)
|
||||||
r.index.Add(*ref, metadata)
|
r.index.Add(*ref, metadata)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -185,7 +185,7 @@ func (r *fileIndexer) addFileToIndex(path string, info os.FileInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := file.NewMetadataFromPath(path, info)
|
metadata := NewMetadataFromPath(path, info)
|
||||||
r.index.Add(*ref, metadata)
|
r.index.Add(*ref, metadata)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
20
syft/internal/fileresolver/get_xid.go
Normal file
20
syft/internal/fileresolver/get_xid.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package fileresolver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getXid is the UID GID system info for unix
|
||||||
|
func getXid(info os.FileInfo) (uid, gid int) {
|
||||||
|
uid = -1
|
||||||
|
gid = -1
|
||||||
|
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
|
||||||
|
uid = int(stat.Uid)
|
||||||
|
gid = int(stat.Gid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uid, gid
|
||||||
|
}
|
||||||
12
syft/internal/fileresolver/get_xid_win.go
Normal file
12
syft/internal/fileresolver/get_xid_win.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package fileresolver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getXid is a placeholder for windows file information
|
||||||
|
func getXid(info os.FileInfo) (uid, gid int) {
|
||||||
|
return -1, -1
|
||||||
|
}
|
||||||
44
syft/internal/fileresolver/metadata.go
Normal file
44
syft/internal/fileresolver/metadata.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package fileresolver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/anchore/stereoscope/pkg/file"
|
||||||
|
"github.com/anchore/syft/internal"
|
||||||
|
"github.com/anchore/syft/syft/internal/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMetadataFromPath(path string, info os.FileInfo) file.Metadata {
|
||||||
|
var mimeType string
|
||||||
|
uid, gid := getXid(info)
|
||||||
|
|
||||||
|
ty := file.TypeFromMode(info.Mode())
|
||||||
|
|
||||||
|
if ty == file.TypeRegular {
|
||||||
|
usablePath := path
|
||||||
|
// denormalize the path back to windows so we can open the file
|
||||||
|
if windows.HostRunningOnWindows() {
|
||||||
|
usablePath = windows.FromPosix(usablePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(usablePath)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: it may be that the file is inaccessible, however, this is not an error or a warning. In the future we need to track these as known-unknowns
|
||||||
|
f = nil
|
||||||
|
} else {
|
||||||
|
defer internal.CloseAndLogError(f, usablePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
mimeType = file.MIMEType(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
return file.Metadata{
|
||||||
|
FileInfo: info,
|
||||||
|
Path: path,
|
||||||
|
Type: ty,
|
||||||
|
// unsupported across platforms
|
||||||
|
UserID: uid,
|
||||||
|
GroupID: gid,
|
||||||
|
MIMEType: mimeType,
|
||||||
|
}
|
||||||
|
}
|
||||||
50
syft/internal/fileresolver/metadata_test.go
Normal file
50
syft/internal/fileresolver/metadata_test.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package fileresolver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/stereoscope/pkg/file"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFileMetadataFromPath(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
path string
|
||||||
|
expectedType file.Type
|
||||||
|
expectedMIMEType string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
path: "test-fixtures/symlinks-simple/readme",
|
||||||
|
expectedType: file.TypeRegular,
|
||||||
|
expectedMIMEType: "text/plain",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "test-fixtures/symlinks-simple/link_to_new_readme",
|
||||||
|
expectedType: file.TypeSymLink,
|
||||||
|
expectedMIMEType: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "test-fixtures/symlinks-simple/link_to_link_to_new_readme",
|
||||||
|
expectedType: file.TypeSymLink,
|
||||||
|
expectedMIMEType: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "test-fixtures/symlinks-simple",
|
||||||
|
expectedType: file.TypeDirectory,
|
||||||
|
expectedMIMEType: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.path, func(t *testing.T) {
|
||||||
|
info, err := os.Lstat(test.path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
actual := NewMetadataFromPath(test.path, info)
|
||||||
|
assert.Equal(t, test.expectedMIMEType, actual.MIMEType, "unexpected MIME type for %s", test.path)
|
||||||
|
assert.Equal(t, test.expectedType, actual.Type, "unexpected type for %s", test.path)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
version "github.com/bitnami/go-version/pkg/version"
|
"github.com/bitnami/go-version/pkg/version"
|
||||||
|
|
||||||
"github.com/anchore/packageurl-go"
|
"github.com/anchore/packageurl-go"
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
|||||||
@ -2,17 +2,21 @@ package dotnet
|
|||||||
|
|
||||||
type CatalogerConfig struct {
|
type CatalogerConfig struct {
|
||||||
// DepPackagesMustHaveDLL allows for deps.json packages to be included only if there is a DLL on disk for that package.
|
// DepPackagesMustHaveDLL allows for deps.json packages to be included only if there is a DLL on disk for that package.
|
||||||
|
// app-config: dotnet.dep-packages-must-have-dll
|
||||||
DepPackagesMustHaveDLL bool `mapstructure:"dep-packages-must-have-dll" json:"dep-packages-must-have-dll" yaml:"dep-packages-must-have-dll"`
|
DepPackagesMustHaveDLL bool `mapstructure:"dep-packages-must-have-dll" json:"dep-packages-must-have-dll" yaml:"dep-packages-must-have-dll"`
|
||||||
|
|
||||||
// DepPackagesMustClaimDLL allows for deps.json packages to be included only if there is a runtime/resource DLL claimed in the deps.json targets section.
|
// DepPackagesMustClaimDLL allows for deps.json packages to be included only if there is a runtime/resource DLL claimed in the deps.json targets section.
|
||||||
// This does not require such claimed DLLs to exist on disk. The behavior of this
|
// This does not require such claimed DLLs to exist on disk. The behavior of this
|
||||||
|
// app-config: dotnet.dep-packages-must-claim-dll
|
||||||
DepPackagesMustClaimDLL bool `mapstructure:"dep-packages-must-claim-dll" json:"dep-packages-must-claim-dll" yaml:"dep-packages-must-claim-dll"`
|
DepPackagesMustClaimDLL bool `mapstructure:"dep-packages-must-claim-dll" json:"dep-packages-must-claim-dll" yaml:"dep-packages-must-claim-dll"`
|
||||||
|
|
||||||
// PropagateDLLClaimsToParents allows for deps.json packages to be included if any child (transitive) package claims a DLL. This applies to both the claims configuration and evidence-on-disk configurations.
|
// PropagateDLLClaimsToParents allows for deps.json packages to be included if any child (transitive) package claims a DLL. This applies to both the claims configuration and evidence-on-disk configurations.
|
||||||
|
// app-config: dotnet.propagate-dll-claims-to-parents
|
||||||
PropagateDLLClaimsToParents bool `mapstructure:"propagate-dll-claims-to-parents" json:"propagate-dll-claims-to-parents" yaml:"propagate-dll-claims-to-parents"`
|
PropagateDLLClaimsToParents bool `mapstructure:"propagate-dll-claims-to-parents" json:"propagate-dll-claims-to-parents" yaml:"propagate-dll-claims-to-parents"`
|
||||||
|
|
||||||
// RelaxDLLClaimsWhenBundlingDetected will look for indications of IL bundle tooling via deps.json package names
|
// RelaxDLLClaimsWhenBundlingDetected will look for indications of IL bundle tooling via deps.json package names
|
||||||
// and, if found (and this config option is enabled), will relax the DepPackagesMustClaimDLL value to `false` only in those cases.
|
// and, if found (and this config option is enabled), will relax the DepPackagesMustClaimDLL value to `false` only in those cases.
|
||||||
|
// app-config: dotnet.relax-dll-claims-when-bundling-detected
|
||||||
RelaxDLLClaimsWhenBundlingDetected bool `mapstructure:"relax-dll-claims-when-bundling-detected" json:"relax-dll-claims-when-bundling-detected" yaml:"relax-dll-claims-when-bundling-detected"`
|
RelaxDLLClaimsWhenBundlingDetected bool `mapstructure:"relax-dll-claims-when-bundling-detected" json:"relax-dll-claims-when-bundling-detected" yaml:"relax-dll-claims-when-bundling-detected"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,19 +19,48 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type CatalogerConfig struct {
|
type CatalogerConfig struct {
|
||||||
SearchLocalModCacheLicenses bool `yaml:"search-local-mod-cache-licenses" json:"search-local-mod-cache-licenses" mapstructure:"search-local-mod-cache-licenses"`
|
// SearchLocalModCacheLicenses enables searching for go package licenses in the local GOPATH mod cache.
|
||||||
LocalModCacheDir string `yaml:"local-mod-cache-dir" json:"local-mod-cache-dir" mapstructure:"local-mod-cache-dir"`
|
// app-config: golang.search-local-mod-cache-licenses
|
||||||
SearchLocalVendorLicenses bool `yaml:"search-local-vendor-licenses" json:"search-local-vendor-licenses" mapstructure:"search-local-vendor-licenses"`
|
SearchLocalModCacheLicenses bool `yaml:"search-local-mod-cache-licenses" json:"search-local-mod-cache-licenses" mapstructure:"search-local-mod-cache-licenses"`
|
||||||
LocalVendorDir string `yaml:"local-vendor-dir" json:"local-vendor-dir" mapstructure:"local-vendor-dir"`
|
|
||||||
SearchRemoteLicenses bool `yaml:"search-remote-licenses" json:"search-remote-licenses" mapstructure:"search-remote-licenses"`
|
// LocalModCacheDir specifies the location of the local go module cache directory. When not set, syft will attempt to discover the GOPATH env or default to $HOME/go.
|
||||||
Proxies []string `yaml:"proxies,omitempty" json:"proxies,omitempty" mapstructure:"proxies"`
|
// app-config: golang.local-mod-cache-dir
|
||||||
NoProxy []string `yaml:"no-proxy,omitempty" json:"no-proxy,omitempty" mapstructure:"no-proxy"`
|
LocalModCacheDir string `yaml:"local-mod-cache-dir" json:"local-mod-cache-dir" mapstructure:"local-mod-cache-dir"`
|
||||||
MainModuleVersion MainModuleVersionConfig `yaml:"main-module-version" json:"main-module-version" mapstructure:"main-module-version"`
|
|
||||||
|
// SearchLocalVendorLicenses enables searching for go package licenses in the local vendor directory relative to the go.mod file.
|
||||||
|
// app-config: golang.search-local-vendor-licenses
|
||||||
|
SearchLocalVendorLicenses bool `yaml:"search-local-vendor-licenses" json:"search-local-vendor-licenses" mapstructure:"search-local-vendor-licenses"`
|
||||||
|
|
||||||
|
// LocalVendorDir specifies the location of the local vendor directory. When not set, syft will search for a vendor directory relative to the go.mod file.
|
||||||
|
// app-config: golang.local-vendor-dir
|
||||||
|
LocalVendorDir string `yaml:"local-vendor-dir" json:"local-vendor-dir" mapstructure:"local-vendor-dir"`
|
||||||
|
|
||||||
|
// SearchRemoteLicenses enables downloading go package licenses from the upstream go proxy (typically proxy.golang.org).
|
||||||
|
// app-config: golang.search-remote-licenses
|
||||||
|
SearchRemoteLicenses bool `yaml:"search-remote-licenses" json:"search-remote-licenses" mapstructure:"search-remote-licenses"`
|
||||||
|
|
||||||
|
// Proxies is a list of go module proxies to use when fetching go module metadata and licenses. When not set, syft will use the GOPROXY env or default to https://proxy.golang.org,direct.
|
||||||
|
// app-config: golang.proxy
|
||||||
|
Proxies []string `yaml:"proxies,omitempty" json:"proxies,omitempty" mapstructure:"proxies"`
|
||||||
|
|
||||||
|
// NoProxy is a list of glob patterns that match go module names that should not be fetched from the go proxy. When not set, syft will use the GOPRIVATE and GONOPROXY env vars.
|
||||||
|
// app-config: golang.no-proxy
|
||||||
|
NoProxy []string `yaml:"no-proxy,omitempty" json:"no-proxy,omitempty" mapstructure:"no-proxy"`
|
||||||
|
|
||||||
|
MainModuleVersion MainModuleVersionConfig `yaml:"main-module-version" json:"main-module-version" mapstructure:"main-module-version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MainModuleVersionConfig struct {
|
type MainModuleVersionConfig struct {
|
||||||
FromLDFlags bool `yaml:"from-ld-flags" json:"from-ld-flags" mapstructure:"from-ld-flags"`
|
// FromLDFlags enables parsing the main module version from the -ldflags build settings.
|
||||||
FromContents bool `yaml:"from-contents" json:"from-contents" mapstructure:"from-contents"`
|
// app-config: golang.main-module-version.from-ld-flags
|
||||||
|
FromLDFlags bool `yaml:"from-ld-flags" json:"from-ld-flags" mapstructure:"from-ld-flags"`
|
||||||
|
|
||||||
|
// FromContents enables parsing the main module version from the binary contents. This is useful when the version is embedded in the binary but not in the build settings.
|
||||||
|
// app-config: golang.main-module-version.from-contents
|
||||||
|
FromContents bool `yaml:"from-contents" json:"from-contents" mapstructure:"from-contents"`
|
||||||
|
|
||||||
|
// FromBuildSettings enables parsing the main module version from the go build settings.
|
||||||
|
// app-config: golang.main-module-version.from-build-settings
|
||||||
FromBuildSettings bool `yaml:"from-build-settings" json:"from-build-settings" mapstructure:"from-build-settings"`
|
FromBuildSettings bool `yaml:"from-build-settings" json:"from-build-settings" mapstructure:"from-build-settings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -336,6 +336,9 @@ func (p *CatalogTester) assertPkgs(t *testing.T, pkgs []pkg.Package, relationshi
|
|||||||
opts = append(opts, p.compareOptions...)
|
opts = append(opts, p.compareOptions...)
|
||||||
opts = append(opts, cmp.Reporter(&r))
|
opts = append(opts, cmp.Reporter(&r))
|
||||||
|
|
||||||
|
// ignore the "FoundBy" field on relationships as it is set in the generic cataloger before it's presence on the relationship
|
||||||
|
opts = append(opts, cmpopts.IgnoreFields(pkg.Package{}, "FoundBy"))
|
||||||
|
|
||||||
// order should not matter
|
// order should not matter
|
||||||
relationship.Sort(p.expectedRelationships)
|
relationship.Sort(p.expectedRelationships)
|
||||||
relationship.Sort(relationships)
|
relationship.Sort(relationships)
|
||||||
|
|||||||
@ -263,7 +263,7 @@ func (j *archiveParser) discoverMainPackage(ctx context.Context) (*pkg.Package,
|
|||||||
}
|
}
|
||||||
var pkgPomProject *pkg.JavaPomProject
|
var pkgPomProject *pkg.JavaPomProject
|
||||||
if parsedPom != nil {
|
if parsedPom != nil {
|
||||||
pkgPomProject = newPomProject(ctx, nil, parsedPom.path, parsedPom.project)
|
pkgPomProject = newPomProject(ctx, j.maven, parsedPom.path, parsedPom.project)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pkg.Package{
|
return &pkg.Package{
|
||||||
|
|||||||
@ -1632,3 +1632,26 @@ func Test_corruptJarArchive(t *testing.T) {
|
|||||||
WithError().
|
WithError().
|
||||||
TestParser(t, ap.parseJavaArchive)
|
TestParser(t, ap.parseJavaArchive)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_jarPomPropertyResolutionDoesNotPanic(t *testing.T) {
|
||||||
|
jarName := generateJavaMetadataJarFixture(t, "commons-lang3-3.12.0", "jar")
|
||||||
|
fixture, err := os.Open(jarName)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ctx := context.TODO()
|
||||||
|
// setup parser
|
||||||
|
ap, cleanupFn, err := newJavaArchiveParser(
|
||||||
|
ctx,
|
||||||
|
file.LocationReadCloser{
|
||||||
|
Location: file.NewLocation(fixture.Name()),
|
||||||
|
ReadCloser: fixture,
|
||||||
|
}, false, ArchiveCatalogerConfig{
|
||||||
|
UseMavenLocalRepository: true,
|
||||||
|
MavenLocalRepositoryDir: "internal/maven/test-fixtures/maven-repo",
|
||||||
|
})
|
||||||
|
defer cleanupFn()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = ap.parse(ctx, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|||||||
@ -41,11 +41,14 @@ func NewPomCataloger(cfg ArchiveCatalogerConfig) pkg.Cataloger {
|
|||||||
// Note: Older versions of lockfiles aren't supported yet
|
// Note: Older versions of lockfiles aren't supported yet
|
||||||
func NewGradleLockfileCataloger() pkg.Cataloger {
|
func NewGradleLockfileCataloger() pkg.Cataloger {
|
||||||
return generic.NewCataloger("java-gradle-lockfile-cataloger").
|
return generic.NewCataloger("java-gradle-lockfile-cataloger").
|
||||||
WithParserByGlobs(parseGradleLockfile, gradleLockfileGlob)
|
WithParserByGlobs(parseGradleLockfile, "**/gradle.lockfile*")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewJvmDistributionCataloger returns packages representing JDK/JRE installations (of multiple distribution types).
|
// NewJvmDistributionCataloger returns packages representing JDK/JRE installations (of multiple distribution types).
|
||||||
func NewJvmDistributionCataloger() pkg.Cataloger {
|
func NewJvmDistributionCataloger() pkg.Cataloger {
|
||||||
return generic.NewCataloger("java-jvm-cataloger").
|
return generic.NewCataloger("java-jvm-cataloger").
|
||||||
WithParserByGlobs(parseJVMRelease, jvmReleaseGlob)
|
// this is a very permissive glob that will match more than just the JVM release file.
|
||||||
|
// we started with "**/{java,jvm}/*/release", but this prevents scanning JVM archive contents (e.g. jdk8u402.zip).
|
||||||
|
// this approach lets us check more files for JVM release info, but be rather silent about errors.
|
||||||
|
WithParserByGlobs(parseJVMRelease, "**/release")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,12 +9,30 @@ import (
|
|||||||
|
|
||||||
type ArchiveCatalogerConfig struct {
|
type ArchiveCatalogerConfig struct {
|
||||||
cataloging.ArchiveSearchConfig `yaml:",inline" json:"" mapstructure:",squash"`
|
cataloging.ArchiveSearchConfig `yaml:",inline" json:"" mapstructure:",squash"`
|
||||||
UseNetwork bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"`
|
|
||||||
UseMavenLocalRepository bool `yaml:"use-maven-localrepository" json:"use-maven-localrepository" mapstructure:"use-maven-localrepository"`
|
// UseNetwork enables network operations for java package metadata enrichment, such as fetching parent POMs and license information.
|
||||||
MavenLocalRepositoryDir string `yaml:"maven-localrepository-dir" json:"maven-localrepository-dir" mapstructure:"maven-localrepository-dir"`
|
// app-config: java.use-network
|
||||||
MavenBaseURL string `yaml:"maven-base-url" json:"maven-base-url" mapstructure:"maven-base-url"`
|
UseNetwork bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"`
|
||||||
MaxParentRecursiveDepth int `yaml:"max-parent-recursive-depth" json:"max-parent-recursive-depth" mapstructure:"max-parent-recursive-depth"`
|
|
||||||
ResolveTransitiveDependencies bool `yaml:"resolve-transitive-dependencies" json:"resolve-transitive-dependencies" mapstructure:"resolve-transitive-dependencies"`
|
// UseMavenLocalRepository enables searching the local maven repository (~/.m2/repository by default) for parent POMs and other metadata.
|
||||||
|
// app-config: java.use-maven-local-repository
|
||||||
|
UseMavenLocalRepository bool `yaml:"use-maven-localrepository" json:"use-maven-localrepository" mapstructure:"use-maven-localrepository"`
|
||||||
|
|
||||||
|
// MavenLocalRepositoryDir specifies the location of the local maven repository. When not set, defaults to ~/.m2/repository.
|
||||||
|
// app-config: java.maven-local-repository-dir
|
||||||
|
MavenLocalRepositoryDir string `yaml:"maven-localrepository-dir" json:"maven-localrepository-dir" mapstructure:"maven-localrepository-dir"`
|
||||||
|
|
||||||
|
// MavenBaseURL specifies the base URL(s) to use for fetching POMs and metadata from maven central or other repositories. When not set, defaults to https://repo1.maven.org/maven2.
|
||||||
|
// app-config: java.maven-url
|
||||||
|
MavenBaseURL string `yaml:"maven-base-url" json:"maven-base-url" mapstructure:"maven-base-url"`
|
||||||
|
|
||||||
|
// MaxParentRecursiveDepth limits how many parent POMs will be fetched recursively before stopping. This prevents infinite loops or excessively deep parent chains.
|
||||||
|
// app-config: java.max-parent-recursive-depth
|
||||||
|
MaxParentRecursiveDepth int `yaml:"max-parent-recursive-depth" json:"max-parent-recursive-depth" mapstructure:"max-parent-recursive-depth"`
|
||||||
|
|
||||||
|
// ResolveTransitiveDependencies enables resolving transitive dependencies for java packages found within archives.
|
||||||
|
// app-config: java.resolve-transitive-dependencies
|
||||||
|
ResolveTransitiveDependencies bool `yaml:"resolve-transitive-dependencies" json:"resolve-transitive-dependencies" mapstructure:"resolve-transitive-dependencies"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultArchiveCatalogerConfig() ArchiveCatalogerConfig {
|
func DefaultArchiveCatalogerConfig() ArchiveCatalogerConfig {
|
||||||
|
|||||||
@ -11,8 +11,6 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
const gradleLockfileGlob = "**/gradle.lockfile*"
|
|
||||||
|
|
||||||
// lockfileDependency represents a single dependency in the gradle.lockfile file
|
// lockfileDependency represents a single dependency in the gradle.lockfile file
|
||||||
type lockfileDependency struct {
|
type lockfileDependency struct {
|
||||||
Group string
|
Group string
|
||||||
|
|||||||
@ -22,10 +22,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// this is a very permissive glob that will match more than just the JVM release file.
|
|
||||||
// we started with "**/{java,jvm}/*/release", but this prevents scanning JVM archive contents (e.g. jdk8u402.zip).
|
|
||||||
// this approach lets us check more files for JVM release info, but be rather silent about errors.
|
|
||||||
jvmReleaseGlob = "**/release"
|
|
||||||
oracleVendor = "oracle"
|
oracleVendor = "oracle"
|
||||||
openJdkProduct = "openjdk"
|
openJdkProduct = "openjdk"
|
||||||
jre = "jre"
|
jre = "jre"
|
||||||
|
|||||||
@ -14,7 +14,7 @@ SPRING_INSTRUMENTATION = spring-instrumentation-4.3.0-1.0
|
|||||||
MULTIPLE_MATCHING = multiple-matching-2.11.5
|
MULTIPLE_MATCHING = multiple-matching-2.11.5
|
||||||
ORG_MULTIPLE_THENAME = org.multiple-thename
|
ORG_MULTIPLE_THENAME = org.multiple-thename
|
||||||
MICRONAUT_AOP = micronaut-aop-4.9.11
|
MICRONAUT_AOP = micronaut-aop-4.9.11
|
||||||
|
COMMONS_LANG3 = commons-lang3-3.12.0
|
||||||
|
|
||||||
.DEFAULT_GOAL := fixtures
|
.DEFAULT_GOAL := fixtures
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ fixtures: $(CACHE_DIR)
|
|||||||
# requirement 2: 'fingerprint' goal to determine if the fixture input that indicates any existing cache should be busted
|
# requirement 2: 'fingerprint' goal to determine if the fixture input that indicates any existing cache should be busted
|
||||||
fingerprint: $(FINGERPRINT_FILE)
|
fingerprint: $(FINGERPRINT_FILE)
|
||||||
|
|
||||||
$(CACHE_DIR): $(CACHE_DIR)/$(JACKSON_CORE).jar $(CACHE_DIR)/$(SBT_JACKSON_CORE).jar $(CACHE_DIR)/$(OPENSAML_CORE).jar $(CACHE_DIR)/$(API_ALL_SOURCES).jar $(CACHE_DIR)/$(SPRING_INSTRUMENTATION).jar $(CACHE_DIR)/$(MULTIPLE_MATCHING).jar $(CACHE_DIR)/$(MICRONAUT_AOP).jar
|
$(CACHE_DIR): $(CACHE_DIR)/$(JACKSON_CORE).jar $(CACHE_DIR)/$(SBT_JACKSON_CORE).jar $(CACHE_DIR)/$(OPENSAML_CORE).jar $(CACHE_DIR)/$(API_ALL_SOURCES).jar $(CACHE_DIR)/$(SPRING_INSTRUMENTATION).jar $(CACHE_DIR)/$(MULTIPLE_MATCHING).jar $(CACHE_DIR)/$(MICRONAUT_AOP).jar $(CACHE_DIR)/$(COMMONS_LANG3).jar
|
||||||
|
|
||||||
$(CACHE_DIR)/$(JACKSON_CORE).jar:
|
$(CACHE_DIR)/$(JACKSON_CORE).jar:
|
||||||
mkdir -p $(CACHE_DIR)
|
mkdir -p $(CACHE_DIR)
|
||||||
@ -58,6 +58,10 @@ $(CACHE_DIR)/$(MICRONAUT_AOP).jar:
|
|||||||
mkdir -p $(CACHE_DIR)
|
mkdir -p $(CACHE_DIR)
|
||||||
cd $(MICRONAUT_AOP) && zip -r $(CACHE_PATH)/$(MICRONAUT_AOP).jar .
|
cd $(MICRONAUT_AOP) && zip -r $(CACHE_PATH)/$(MICRONAUT_AOP).jar .
|
||||||
|
|
||||||
|
$(CACHE_DIR)/$(COMMONS_LANG3).jar:
|
||||||
|
mkdir -p $(CACHE_DIR)
|
||||||
|
cd $(COMMONS_LANG3) && zip -r $(CACHE_PATH)/$(COMMONS_LANG3).jar .
|
||||||
|
|
||||||
# Jenkins plugins typically do not have the version included in the archive name,
|
# 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
|
# so it is important to not include it in the generated test fixture
|
||||||
$(CACHE_DIR)/gradle.hpi:
|
$(CACHE_DIR)/gradle.hpi:
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-parent</artifactId>
|
||||||
|
<version>54</version>
|
||||||
|
</parent>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${commons.release.version}</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<name>JUnit 5 (Bill of Materials)</name>
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>Eclipse Public License v2.0</name>
|
||||||
|
<url>https://www.eclipse.org/legal/epl-v20.html</url>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
<scm>
|
||||||
|
<connection>scm:git:git://github.com/junit-team/junit5.git</connection>
|
||||||
|
<developerConnection>scm:git:git://github.com/junit-team/junit5.git</developerConnection>
|
||||||
|
<url>https://github.com/junit-team/junit5</url>
|
||||||
|
</scm>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.vintage</groupId>
|
||||||
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
|
<version>${commons.release.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@ -18,8 +18,9 @@ func NewPackageCataloger() pkg.Cataloger {
|
|||||||
func NewLockCataloger(cfg CatalogerConfig) pkg.Cataloger {
|
func NewLockCataloger(cfg CatalogerConfig) pkg.Cataloger {
|
||||||
yarnLockAdapter := newGenericYarnLockAdapter(cfg)
|
yarnLockAdapter := newGenericYarnLockAdapter(cfg)
|
||||||
packageLockAdapter := newGenericPackageLockAdapter(cfg)
|
packageLockAdapter := newGenericPackageLockAdapter(cfg)
|
||||||
|
pnpmLockAdapter := newGenericPnpmLockAdapter(cfg)
|
||||||
return generic.NewCataloger("javascript-lock-cataloger").
|
return generic.NewCataloger("javascript-lock-cataloger").
|
||||||
WithParserByGlobs(packageLockAdapter.parsePackageLock, "**/package-lock.json").
|
WithParserByGlobs(packageLockAdapter.parsePackageLock, "**/package-lock.json").
|
||||||
WithParserByGlobs(yarnLockAdapter.parseYarnLock, "**/yarn.lock").
|
WithParserByGlobs(yarnLockAdapter.parseYarnLock, "**/yarn.lock").
|
||||||
WithParserByGlobs(parsePnpmLock, "**/pnpm-lock.yaml")
|
WithParserByGlobs(pnpmLockAdapter.parsePnpmLock, "**/pnpm-lock.yaml")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,15 @@ package javascript
|
|||||||
const npmBaseURL = "https://registry.npmjs.org"
|
const npmBaseURL = "https://registry.npmjs.org"
|
||||||
|
|
||||||
type CatalogerConfig struct {
|
type CatalogerConfig struct {
|
||||||
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
|
// SearchRemoteLicenses enables querying the NPM registry API to retrieve license information for packages that are missing license data in their local metadata.
|
||||||
NPMBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
|
// app-config: javascript.search-remote-licenses
|
||||||
IncludeDevDependencies bool `json:"include-dev-dependencies" yaml:"include-dev-dependencies" mapstructure:"include-dev-dependencies"`
|
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
|
||||||
|
// NPMBaseURL specifies the base URL for the NPM registry API used when searching for remote license information.
|
||||||
|
// app-config: javascript.npm-base-url
|
||||||
|
NPMBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
|
||||||
|
// IncludeDevDependencies controls whether development dependencies should be included in the catalog results, in addition to production dependencies.
|
||||||
|
// app-config: javascript.include-dev-dependencies
|
||||||
|
IncludeDevDependencies bool `json:"include-dev-dependencies" yaml:"include-dev-dependencies" mapstructure:"include-dev-dependencies"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultCatalogerConfig() CatalogerConfig {
|
func DefaultCatalogerConfig() CatalogerConfig {
|
||||||
|
|||||||
@ -107,7 +107,7 @@ func newPackageLockV1Package(ctx context.Context, cfg CatalogerConfig, resolver
|
|||||||
licenseSet = pkg.NewLicenseSet(licenses...)
|
licenseSet = pkg.NewLicenseSet(licenses...)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("unable to extract licenses from javascript yarn.lock for package %s:%s: %+v", name, version, err)
|
log.Debugf("unable to extract licenses from javascript package-lock.json for package %s:%s: %+v", name, version, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ func newPackageLockV2Package(ctx context.Context, cfg CatalogerConfig, resolver
|
|||||||
licenseSet = pkg.NewLicenseSet(licenses...)
|
licenseSet = pkg.NewLicenseSet(licenses...)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("unable to extract licenses from javascript yarn.lock for package %s:%s: %+v", name, u.Version, err)
|
log.Debugf("unable to extract licenses from javascript package-lock.json for package %s:%s: %+v", name, u.Version, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +161,19 @@ func newPackageLockV2Package(ctx context.Context, cfg CatalogerConfig, resolver
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPnpmPackage(ctx context.Context, resolver file.Resolver, location file.Location, name, version string) pkg.Package {
|
func newPnpmPackage(ctx context.Context, cfg CatalogerConfig, resolver file.Resolver, location file.Location, name, version string) pkg.Package {
|
||||||
|
var licenseSet pkg.LicenseSet
|
||||||
|
|
||||||
|
if cfg.SearchRemoteLicenses {
|
||||||
|
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
|
||||||
|
if err == nil && license != "" {
|
||||||
|
licenses := pkg.NewLicensesFromValuesWithContext(ctx, license)
|
||||||
|
licenseSet = pkg.NewLicenseSet(licenses...)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("unable to extract licenses from javascript pnpm-lock.yaml for package %s:%s: %+v", name, version, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return finalizeLockPkg(
|
return finalizeLockPkg(
|
||||||
ctx,
|
ctx,
|
||||||
resolver,
|
resolver,
|
||||||
@ -169,6 +181,7 @@ func newPnpmPackage(ctx context.Context, resolver file.Resolver, location file.L
|
|||||||
pkg.Package{
|
pkg.Package{
|
||||||
Name: name,
|
Name: name,
|
||||||
Version: version,
|
Version: version,
|
||||||
|
Licenses: licenseSet,
|
||||||
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||||
PURL: packageURL(name, version),
|
PURL: packageURL(name, version),
|
||||||
Language: pkg.JavaScript,
|
Language: pkg.JavaScript,
|
||||||
|
|||||||
@ -18,9 +18,6 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// integrity check
|
|
||||||
var _ generic.Parser = parsePnpmLock
|
|
||||||
|
|
||||||
// pnpmPackage holds the raw name and version extracted from the lockfile.
|
// pnpmPackage holds the raw name and version extracted from the lockfile.
|
||||||
type pnpmPackage struct {
|
type pnpmPackage struct {
|
||||||
Name string
|
Name string
|
||||||
@ -45,6 +42,16 @@ type pnpmV9LockYaml struct {
|
|||||||
Packages map[string]interface{} `yaml:"packages"`
|
Packages map[string]interface{} `yaml:"packages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type genericPnpmLockAdapter struct {
|
||||||
|
cfg CatalogerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGenericPnpmLockAdapter(cfg CatalogerConfig) genericPnpmLockAdapter {
|
||||||
|
return genericPnpmLockAdapter{
|
||||||
|
cfg: cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse implements the pnpmLockfileParser interface for v6-v8 lockfiles.
|
// Parse implements the pnpmLockfileParser interface for v6-v8 lockfiles.
|
||||||
func (p *pnpmV6LockYaml) Parse(version float64, data []byte) ([]pnpmPackage, error) {
|
func (p *pnpmV6LockYaml) Parse(version float64, data []byte) ([]pnpmPackage, error) {
|
||||||
if err := yaml.Unmarshal(data, p); err != nil {
|
if err := yaml.Unmarshal(data, p); err != nil {
|
||||||
@ -116,7 +123,7 @@ func newPnpmLockfileParser(version float64) pnpmLockfileParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parsePnpmLock is the main parser function for pnpm-lock.yaml files.
|
// parsePnpmLock is the main parser function for pnpm-lock.yaml files.
|
||||||
func parsePnpmLock(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
func (a genericPnpmLockAdapter) parsePnpmLock(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
data, err := io.ReadAll(reader)
|
data, err := io.ReadAll(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to load pnpm-lock.yaml file: %w", err)
|
return nil, nil, fmt.Errorf("failed to load pnpm-lock.yaml file: %w", err)
|
||||||
@ -142,7 +149,7 @@ func parsePnpmLock(ctx context.Context, resolver file.Resolver, _ *generic.Envir
|
|||||||
|
|
||||||
packages := make([]pkg.Package, len(pnpmPkgs))
|
packages := make([]pkg.Package, len(pnpmPkgs))
|
||||||
for i, p := range pnpmPkgs {
|
for i, p := range pnpmPkgs {
|
||||||
packages[i] = newPnpmPackage(ctx, resolver, reader.Location, p.Name, p.Version)
|
packages[i] = newPnpmPackage(ctx, a.cfg, resolver, reader.Location, p.Name, p.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
return packages, nil, unknown.IfEmptyf(packages, "unable to determine packages")
|
return packages, nil, unknown.IfEmptyf(packages, "unable to determine packages")
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
package javascript
|
package javascript
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
@ -50,7 +55,8 @@ func TestParsePnpmLock(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgtest.TestFileParser(t, fixture, parsePnpmLock, expectedPkgs, expectedRelationships)
|
adapter := newGenericPnpmLockAdapter(CatalogerConfig{})
|
||||||
|
pkgtest.TestFileParser(t, fixture, adapter.parsePnpmLock, expectedPkgs, expectedRelationships)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsePnpmV6Lock(t *testing.T) {
|
func TestParsePnpmV6Lock(t *testing.T) {
|
||||||
@ -142,7 +148,8 @@ func TestParsePnpmV6Lock(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgtest.TestFileParser(t, fixture, parsePnpmLock, expectedPkgs, expectedRelationships)
|
adapter := newGenericPnpmLockAdapter(CatalogerConfig{})
|
||||||
|
pkgtest.TestFileParser(t, fixture, adapter.parsePnpmLock, expectedPkgs, expectedRelationships)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsePnpmLockV9(t *testing.T) {
|
func TestParsePnpmLockV9(t *testing.T) {
|
||||||
@ -184,14 +191,101 @@ func TestParsePnpmLockV9(t *testing.T) {
|
|||||||
Type: pkg.NpmPkg,
|
Type: pkg.NpmPkg,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
adapter := newGenericPnpmLockAdapter(CatalogerConfig{})
|
||||||
// TODO: no relationships are under test
|
// TODO: no relationships are under test
|
||||||
pkgtest.TestFileParser(t, fixture, parsePnpmLock, expected, expectedRelationships)
|
pkgtest.TestFileParser(t, fixture, adapter.parsePnpmLock, expected, expectedRelationships)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSearchPnpmForLicenses(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
fixture := "test-fixtures/pnpm-remote/pnpm-lock.yaml"
|
||||||
|
locations := file.NewLocationSet(file.NewLocation(fixture))
|
||||||
|
mux, url, teardown := setupNpmRegistry()
|
||||||
|
defer teardown()
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fixture string
|
||||||
|
config CatalogerConfig
|
||||||
|
requestHandlers []handlerPath
|
||||||
|
expectedPackages []pkg.Package
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "search remote licenses returns the expected licenses when search is set to true",
|
||||||
|
config: CatalogerConfig{SearchRemoteLicenses: true},
|
||||||
|
requestHandlers: []handlerPath{
|
||||||
|
{
|
||||||
|
// https://registry.npmjs.org/nanoid/3.3.4
|
||||||
|
path: "/nanoid/3.3.4",
|
||||||
|
handler: generateMockNpmRegistryHandler("test-fixtures/pnpm-remote/registry_response.json"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPackages: []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "nanoid",
|
||||||
|
Version: "3.3.4",
|
||||||
|
Locations: locations,
|
||||||
|
PURL: "pkg:npm/nanoid@3.3.4",
|
||||||
|
Licenses: pkg.NewLicenseSet(pkg.NewLicenseWithContext(ctx, "MIT")),
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.NpmPkg,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
// set up the mock server
|
||||||
|
for _, handler := range tc.requestHandlers {
|
||||||
|
mux.HandleFunc(handler.path, handler.handler)
|
||||||
|
}
|
||||||
|
tc.config.NPMBaseURL = url
|
||||||
|
adapter := newGenericPnpmLockAdapter(tc.config)
|
||||||
|
pkgtest.TestFileParser(t, fixture, adapter.parsePnpmLock, tc.expectedPackages, nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
func Test_corruptPnpmLock(t *testing.T) {
|
func Test_corruptPnpmLock(t *testing.T) {
|
||||||
|
adapter := newGenericPnpmLockAdapter(CatalogerConfig{})
|
||||||
pkgtest.NewCatalogTester().
|
pkgtest.NewCatalogTester().
|
||||||
FromFile(t, "test-fixtures/corrupt/pnpm-lock.yaml").
|
FromFile(t, "test-fixtures/corrupt/pnpm-lock.yaml").
|
||||||
WithError().
|
WithError().
|
||||||
TestParser(t, parsePnpmLock)
|
TestParser(t, adapter.parsePnpmLock)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateMockNpmRegistryHandler(responseFixture string) func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
// Copy the file's content to the response writer
|
||||||
|
file, err := os.Open(responseFixture)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(w, file)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup sets up a test HTTP server for mocking requests to a particular registry.
|
||||||
|
// The returned url is injected into the Config so the client uses the test server.
|
||||||
|
// Tests should register handlers on mux to simulate the expected request/response structure
|
||||||
|
func setupNpmRegistry() (mux *http.ServeMux, serverURL string, teardown func()) {
|
||||||
|
// mux is the HTTP request multiplexer used with the test server.
|
||||||
|
mux = http.NewServeMux()
|
||||||
|
|
||||||
|
// We want to ensure that tests catch mistakes where the endpoint URL is
|
||||||
|
// specified as absolute rather than relative. It only makes a difference
|
||||||
|
// when there's a non-empty base URL path. So, use that. See issue #752.
|
||||||
|
apiHandler := http.NewServeMux()
|
||||||
|
apiHandler.Handle("/", mux)
|
||||||
|
// server is a test HTTP server used to provide mock API responses.
|
||||||
|
server := httptest.NewServer(apiHandler)
|
||||||
|
|
||||||
|
return mux, server.URL, server.Close
|
||||||
}
|
}
|
||||||
|
|||||||
@ -239,7 +239,7 @@ func TestSearchYarnForLicenses(t *testing.T) {
|
|||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
fixture := "test-fixtures/yarn-remote/yarn.lock"
|
fixture := "test-fixtures/yarn-remote/yarn.lock"
|
||||||
locations := file.NewLocationSet(file.NewLocation(fixture))
|
locations := file.NewLocationSet(file.NewLocation(fixture))
|
||||||
mux, url, teardown := setup()
|
mux, url, teardown := setupYarnRegistry()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -255,7 +255,7 @@ func TestSearchYarnForLicenses(t *testing.T) {
|
|||||||
{
|
{
|
||||||
// https://registry.yarnpkg.com/@babel/code-frame/7.10.4
|
// https://registry.yarnpkg.com/@babel/code-frame/7.10.4
|
||||||
path: "/@babel/code-frame/7.10.4",
|
path: "/@babel/code-frame/7.10.4",
|
||||||
handler: generateMockNPMHandler("test-fixtures/yarn-remote/registry_response.json"),
|
handler: generateMockYarnRegistryHandler("test-fixtures/yarn-remote/registry_response.json"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedPackages: []pkg.Package{
|
expectedPackages: []pkg.Package{
|
||||||
@ -445,7 +445,7 @@ func TestParseYarnFindPackageVersions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateMockNPMHandler(responseFixture string) func(w http.ResponseWriter, r *http.Request) {
|
func generateMockYarnRegistryHandler(responseFixture string) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
// Copy the file's content to the response writer
|
// Copy the file's content to the response writer
|
||||||
@ -464,10 +464,10 @@ func generateMockNPMHandler(responseFixture string) func(w http.ResponseWriter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup sets up a test HTTP server for mocking requests to maven central.
|
// setup sets up a test HTTP server for mocking requests to a particular registry.
|
||||||
// The returned url is injected into the Config so the client uses the test server.
|
// The returned url is injected into the Config so the client uses the test server.
|
||||||
// Tests should register handlers on mux to simulate the expected request/response structure
|
// Tests should register handlers on mux to simulate the expected request/response structure
|
||||||
func setup() (mux *http.ServeMux, serverURL string, teardown func()) {
|
func setupYarnRegistry() (mux *http.ServeMux, serverURL string, teardown func()) {
|
||||||
// mux is the HTTP request multiplexer used with the test server.
|
// mux is the HTTP request multiplexer used with the test server.
|
||||||
mux = http.NewServeMux()
|
mux = http.NewServeMux()
|
||||||
|
|
||||||
|
|||||||
11
syft/pkg/cataloger/javascript/test-fixtures/pnpm-remote/pnpm-lock.yaml
generated
Normal file
11
syft/pkg/cataloger/javascript/test-fixtures/pnpm-remote/pnpm-lock.yaml
generated
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
lockfileVersion: 5.4
|
||||||
|
|
||||||
|
specifiers:
|
||||||
|
nanoid: ^3.3.4
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.4
|
||||||
|
|
||||||
|
packages:
|
||||||
|
/nanoid/3.3.4:
|
||||||
|
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
"name": "nanoid",
|
||||||
|
"version": "3.3.4",
|
||||||
|
"keywords": [
|
||||||
|
"uuid",
|
||||||
|
"random",
|
||||||
|
"id",
|
||||||
|
"url"
|
||||||
|
],
|
||||||
|
"author": {
|
||||||
|
"name": "Andrey Sitnik",
|
||||||
|
"email": "andrey@sitnik.ru"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"_id": "nanoid@3.3.4",
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "ai",
|
||||||
|
"email": "andrey@sitnik.ru"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/ai/nanoid#readme",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/ai/nanoid/issues"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"shasum": "730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab",
|
||||||
|
"tarball": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
|
"fileCount": 24,
|
||||||
|
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"sig": "MEQCIEXG2ta5bIaT6snvQFKV+m1KjuF4DaCpp186tcPo8vsRAiB2Eg9/6nKRi4lZOfwQC1fgq4EzrFjU8T+uqwGxWEQE8A==",
|
||||||
|
"keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unpackedSize": 21583,
|
||||||
|
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJicQqNACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp6rw/+IRvv2zOtwi8goF3h1VctIQVWtTtYrobDIVC2W++jyxdbgZoP\r\n2CDj1YWjrr+eM6O6sI1Bj+bF+yoqQ+z8ojtfW3vtRPpjzUf/7Sgs4F2ANshp\r\ne3rqdaQLjpHPriHf6HmPJy3YNJ+7n5TPPGoTEGXAe4eCZdko3XidCMWZdHlf\r\nYQU9CVYiG6mjjORkWw1sYctt8exdcGFMh0QoQq7BEp04QWm04JwvHjUiAgvf\r\nmEQLrNrf9nwzjpnubAJD+1z6fKOc9vUE44MOj2PkPoOr6a+iBBBgwBf45cnj\r\ng8R2G5xzxsRRB0a8XZdp67y3WA8rIaYaUuBFtEWYp7QFoA/tp6AGmHEAhjLa\r\nQKTquG7ejBu21ZsQaxpGc/3WWLEm+7F78GF8CXpQdtg0Kg1eugRotSNnU0SO\r\nPLiyYV4Mw6kXnbVchS5Y+HmcDVEcSBMTve/f1KpmIhJueJ20RCg4MGYZWgI9\r\nNJ1KgH2h4djX4XuoXpcsKnX3oVfinHEMke8sLWXHsMAtOxDipEWgW9cE9hk0\r\n71Y6LAAPBu34pmaj73B0qZiIY7wXxoGWQOCl2STS/VyDG/K9w1T+WiYROu+8\r\nE9Gd+f4qXmdi7Jw6May86DDfauCwBP3gnrB5aeOktCjWsgrrdClN3Hv2pIAN\r\noJcjS3IURf6oeV4+Yw1B5GoJu1Y/6U75fOU=\r\n=IMnM\r\n-----END PGP SIGNATURE-----\r\n"
|
||||||
|
},
|
||||||
|
"main": "index.cjs",
|
||||||
|
"type": "module",
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"module": "index.js",
|
||||||
|
"browser": {
|
||||||
|
"./index.js": "./index.browser.js",
|
||||||
|
"./index.cjs": "./index.browser.cjs",
|
||||||
|
"./async/index.js": "./async/index.browser.js",
|
||||||
|
"./async/index.cjs": "./async/index.browser.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"import": "./index.js",
|
||||||
|
"browser": "./index.browser.js",
|
||||||
|
"default": "./index.js",
|
||||||
|
"require": "./index.cjs"
|
||||||
|
},
|
||||||
|
"./async": {
|
||||||
|
"import": "./async/index.js",
|
||||||
|
"browser": "./async/index.browser.js",
|
||||||
|
"default": "./async/index.js",
|
||||||
|
"require": "./async/index.cjs"
|
||||||
|
},
|
||||||
|
"./index.d.ts": "./index.d.ts",
|
||||||
|
"./non-secure": {
|
||||||
|
"import": "./non-secure/index.js",
|
||||||
|
"default": "./non-secure/index.js",
|
||||||
|
"require": "./non-secure/index.cjs"
|
||||||
|
},
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
"./url-alphabet": {
|
||||||
|
"import": "./url-alphabet/index.js",
|
||||||
|
"default": "./url-alphabet/index.js",
|
||||||
|
"require": "./url-alphabet/index.cjs"
|
||||||
|
},
|
||||||
|
"./async/package.json": "./async/package.json",
|
||||||
|
"./non-secure/package.json": "./non-secure/package.json",
|
||||||
|
"./url-alphabet/package.json": "./url-alphabet/package.json"
|
||||||
|
},
|
||||||
|
"gitHead": "fc5bd0dbba830b1e6f3e572da8e2bc9ddc1b4b44",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "ai",
|
||||||
|
"email": "andrey@sitnik.ru"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"url": "git+https://github.com/ai/nanoid.git",
|
||||||
|
"type": "git"
|
||||||
|
},
|
||||||
|
"_npmVersion": "8.6.0",
|
||||||
|
"description": "A tiny (116 bytes), secure URL-friendly unique string ID generator",
|
||||||
|
"directories": {},
|
||||||
|
"sideEffects": false,
|
||||||
|
"_nodeVersion": "18.0.0",
|
||||||
|
"react-native": "index.js",
|
||||||
|
"_hasShrinkwrap": false,
|
||||||
|
"_npmOperationalInternal": {
|
||||||
|
"tmp": "tmp/nanoid_3.3.4_1651575437375_0.2288595018362154",
|
||||||
|
"host": "s3://npm-registry-packages"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,6 +17,8 @@ import (
|
|||||||
var _ pkg.Cataloger = (*linuxKernelCataloger)(nil)
|
var _ pkg.Cataloger = (*linuxKernelCataloger)(nil)
|
||||||
|
|
||||||
type LinuxKernelCatalogerConfig struct {
|
type LinuxKernelCatalogerConfig struct {
|
||||||
|
// CatalogModules enables cataloging linux kernel modules (*.ko files) in addition to the kernel itself.
|
||||||
|
// app-config: linux-kernel.catalog-modules
|
||||||
CatalogModules bool `yaml:"catalog-modules" json:"catalog-modules" mapstructure:"catalog-modules"`
|
CatalogModules bool `yaml:"catalog-modules" json:"catalog-modules" mapstructure:"catalog-modules"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
// CaptureOwnedFiles determines whether to record the list of files owned by each Nix package discovered in the store. Recording owned files provides more detailed information but increases processing time and memory usage.
|
||||||
|
// app-config: nix.capture-owned-files
|
||||||
CaptureOwnedFiles bool `json:"capture-owned-files" yaml:"capture-owned-files" mapstructure:"capture-owned-files"`
|
CaptureOwnedFiles bool `json:"capture-owned-files" yaml:"capture-owned-files" mapstructure:"capture-owned-files"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import (
|
|||||||
const eggInfoGlob = "**/*.egg-info"
|
const eggInfoGlob = "**/*.egg-info"
|
||||||
|
|
||||||
type CatalogerConfig struct {
|
type CatalogerConfig struct {
|
||||||
|
// GuessUnpinnedRequirements attempts to infer package versions from version constraints when no explicit version is specified in requirements files.
|
||||||
|
// app-config: python.guess-unpinned-requirements
|
||||||
GuessUnpinnedRequirements bool `yaml:"guess-unpinned-requirements" json:"guess-unpinned-requirements" mapstructure:"guess-unpinned-requirements"`
|
GuessUnpinnedRequirements bool `yaml:"guess-unpinned-requirements" json:"guess-unpinned-requirements" mapstructure:"guess-unpinned-requirements"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +30,8 @@ func NewPackageCataloger(cfg CatalogerConfig) pkg.Cataloger {
|
|||||||
WithParserByGlobs(parsePoetryLock, "**/poetry.lock").
|
WithParserByGlobs(parsePoetryLock, "**/poetry.lock").
|
||||||
WithParserByGlobs(parsePipfileLock, "**/Pipfile.lock").
|
WithParserByGlobs(parsePipfileLock, "**/Pipfile.lock").
|
||||||
WithParserByGlobs(parseSetup, "**/setup.py").
|
WithParserByGlobs(parseSetup, "**/setup.py").
|
||||||
WithParserByGlobs(parseUvLock, "**/uv.lock")
|
WithParserByGlobs(parseUvLock, "**/uv.lock").
|
||||||
|
WithParserByGlobs(parsePdmLock, "**/pdm.lock")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInstalledPackageCataloger returns a new cataloger for python packages within egg or wheel installation directories.
|
// NewInstalledPackageCataloger returns a new cataloger for python packages within egg or wheel installation directories.
|
||||||
|
|||||||
@ -454,6 +454,7 @@ func Test_IndexCataloger_Globs(t *testing.T) {
|
|||||||
"src/poetry.lock",
|
"src/poetry.lock",
|
||||||
"src/Pipfile.lock",
|
"src/Pipfile.lock",
|
||||||
"src/uv.lock",
|
"src/uv.lock",
|
||||||
|
"src/pdm.lock",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
140
syft/pkg/cataloger/python/parse_pdm_lock.go
Normal file
140
syft/pkg/cataloger/python/parse_pdm_lock.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package python
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/scylladb/go-set/strset"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/unknown"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pdmLock struct {
|
||||||
|
Metadata struct {
|
||||||
|
Groups []string `toml:"groups"`
|
||||||
|
Strategy []string `toml:"strategy"`
|
||||||
|
LockVersion string `toml:"lock_version"`
|
||||||
|
ContentHash string `toml:"content_hash"`
|
||||||
|
} `toml:"metadata"`
|
||||||
|
Package []pdmLockPackage `toml:"package"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type pdmLockPackage struct {
|
||||||
|
Name string `toml:"name"`
|
||||||
|
Version string `toml:"version"`
|
||||||
|
RequiresPython string `toml:"requires_python"`
|
||||||
|
Summary string `toml:"summary"`
|
||||||
|
Dependencies []string `toml:"dependencies"`
|
||||||
|
Files []pdmLockPackageFile `toml:"files"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type pdmLockPackageFile struct {
|
||||||
|
File string `toml:"file"`
|
||||||
|
Hash string `toml:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ generic.Parser = parsePdmLock
|
||||||
|
|
||||||
|
// parsePdmLock is a parser function for pdm.lock contents, returning python packages discovered.
|
||||||
|
func parsePdmLock(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
var lock pdmLock
|
||||||
|
_, err := toml.NewDecoder(reader).Decode(&lock)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to parse pdm.lock file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
for _, p := range lock.Package {
|
||||||
|
var files []pkg.PythonFileRecord
|
||||||
|
for _, f := range p.Files {
|
||||||
|
if colonIndex := strings.Index(f.Hash, ":"); colonIndex != -1 {
|
||||||
|
algorithm := f.Hash[:colonIndex]
|
||||||
|
value := f.Hash[colonIndex+1:]
|
||||||
|
|
||||||
|
files = append(files, pkg.PythonFileRecord{
|
||||||
|
Path: f.File,
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: algorithm,
|
||||||
|
Value: value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// only store used part of the dependency information
|
||||||
|
var deps []string
|
||||||
|
for _, dep := range p.Dependencies {
|
||||||
|
// remove environment markers (after semicolon)
|
||||||
|
dep = strings.Split(dep, ";")[0]
|
||||||
|
dep = strings.TrimSpace(dep)
|
||||||
|
if dep != "" {
|
||||||
|
deps = append(deps, dep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pythonPkgMetadata := pkg.PythonPdmLockEntry{
|
||||||
|
Files: files,
|
||||||
|
Summary: p.Summary,
|
||||||
|
Dependencies: deps,
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgs = append(pkgs, newPackageForIndexWithMetadata(
|
||||||
|
p.Name,
|
||||||
|
p.Version,
|
||||||
|
pythonPkgMetadata,
|
||||||
|
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
relationships := buildPdmRelationships(pkgs)
|
||||||
|
|
||||||
|
return pkgs, relationships, unknown.IfEmptyf(pkgs, "unable to determine packages")
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildPdmRelationships(pkgs []pkg.Package) []artifact.Relationship {
|
||||||
|
pkgMap := make(map[string]pkg.Package, len(pkgs))
|
||||||
|
for _, p := range pkgs {
|
||||||
|
pkgMap[p.Name] = p
|
||||||
|
}
|
||||||
|
|
||||||
|
var relationships []artifact.Relationship
|
||||||
|
for _, p := range pkgs {
|
||||||
|
meta, ok := p.Metadata.(pkg.PythonPdmLockEntry)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect unique dependencies
|
||||||
|
added := strset.New()
|
||||||
|
|
||||||
|
for _, depName := range meta.Dependencies {
|
||||||
|
// Handle version specifiers
|
||||||
|
depName = strings.Split(depName, "<")[0]
|
||||||
|
depName = strings.Split(depName, ">")[0]
|
||||||
|
depName = strings.Split(depName, "=")[0]
|
||||||
|
depName = strings.Split(depName, "~")[0]
|
||||||
|
depName = strings.TrimSpace(depName)
|
||||||
|
|
||||||
|
if depName == "" || added.Has(depName) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
added.Add(depName)
|
||||||
|
|
||||||
|
if dep, exists := pkgMap[depName]; exists {
|
||||||
|
relationships = append(relationships, artifact.Relationship{
|
||||||
|
From: dep,
|
||||||
|
To: p,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return relationships
|
||||||
|
}
|
||||||
363
syft/pkg/cataloger/python/parse_pdm_lock_test.go
Normal file
363
syft/pkg/cataloger/python/parse_pdm_lock_test.go
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
package python
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParsePdmLock(t *testing.T) {
|
||||||
|
|
||||||
|
fixture := "test-fixtures/pdm-lock/pdm.lock"
|
||||||
|
locations := file.NewLocationSet(file.NewLocation(fixture))
|
||||||
|
expectedPkgs := []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "certifi",
|
||||||
|
Version: "2025.1.31",
|
||||||
|
PURL: "pkg:pypi/certifi@2025.1.31",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "Python package for providing Mozilla's CA Bundle.",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "chardet",
|
||||||
|
Version: "3.0.4",
|
||||||
|
PURL: "pkg:pypi/chardet@3.0.4",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "Universal encoding detector for Python 2 and 3",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "charset-normalizer",
|
||||||
|
Version: "2.0.12",
|
||||||
|
PURL: "pkg:pypi/charset-normalizer@2.0.12",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet.",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "colorama",
|
||||||
|
Version: "0.3.9",
|
||||||
|
PURL: "pkg:pypi/colorama@0.3.9",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "Cross-platform colored terminal text.",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "idna",
|
||||||
|
Version: "2.7",
|
||||||
|
PURL: "pkg:pypi/idna@2.7",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "Internationalized Domain Names in Applications (IDNA)",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "py",
|
||||||
|
Version: "1.4.34",
|
||||||
|
PURL: "pkg:pypi/py@1.4.34",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "library with cross-python path, ini-parsing, io, code, log facilities",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "2ccb79b01769d99115aa600d7eed99f524bf752bba8f041dc1c184853514655a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "0f2d585d22050e90c7d293b6451c83db097df77871974d90efd5a30dc12fcde3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pytest",
|
||||||
|
Version: "3.2.5",
|
||||||
|
PURL: "pkg:pypi/pytest@3.2.5",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "pytest: simple powerful testing with Python",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "6d5bd4f7113b444c55a3bbb5c738a3dd80d43563d063fc42dcb0aaefbdd78b81",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "241d7e7798d79192a123ceaf64c602b4d233eacf6d6e42ae27caa97f498b7dc6",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Dependencies: []string{
|
||||||
|
"argparse",
|
||||||
|
"colorama",
|
||||||
|
"ordereddict",
|
||||||
|
"py>=1.4.33",
|
||||||
|
"setuptools",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "requests",
|
||||||
|
Version: "2.27.1",
|
||||||
|
PURL: "pkg:pypi/requests@2.27.1",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "Python HTTP for Humans.",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Dependencies: []string{
|
||||||
|
"certifi>=2017.4.17",
|
||||||
|
"chardet<5,>=3.0.2",
|
||||||
|
"charset-normalizer~=2.0.0",
|
||||||
|
"idna<3,>=2.5",
|
||||||
|
"idna<4,>=2.5",
|
||||||
|
"urllib3<1.27,>=1.21.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "setuptools",
|
||||||
|
Version: "39.2.0",
|
||||||
|
PURL: "pkg:pypi/setuptools@39.2.0",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "Easily download, build, install, upgrade, and uninstall Python packages",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "f7cddbb5f5c640311eb00eab6e849f7701fa70bf6a183fc8a2c33dd1d1672fb2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "8fca9275c89964f13da985c3656cb00ba029d7f3916b37990927ffdf264e7926",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "urllib3",
|
||||||
|
Version: "1.26.20",
|
||||||
|
PURL: "pkg:pypi/urllib3@1.26.20",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
Metadata: pkg.PythonPdmLockEntry{
|
||||||
|
Summary: "HTTP library with thread-safe connection pooling, file post, and more.",
|
||||||
|
Files: []pkg.PythonFileRecord{
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "",
|
||||||
|
Digest: &pkg.PythonFileDigest{
|
||||||
|
Algorithm: "sha256",
|
||||||
|
Value: "40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a map for easy lookup of packages by name
|
||||||
|
pkgMap := make(map[string]pkg.Package)
|
||||||
|
for _, p := range expectedPkgs {
|
||||||
|
pkgMap[p.Name] = p
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedRelationships := []artifact.Relationship{
|
||||||
|
// pytest dependencies
|
||||||
|
{
|
||||||
|
From: pkgMap["colorama"],
|
||||||
|
To: pkgMap["pytest"],
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
From: pkgMap["py"],
|
||||||
|
To: pkgMap["pytest"],
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
From: pkgMap["setuptools"],
|
||||||
|
To: pkgMap["pytest"],
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
// requests dependencies
|
||||||
|
{
|
||||||
|
From: pkgMap["certifi"],
|
||||||
|
To: pkgMap["requests"],
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
From: pkgMap["chardet"],
|
||||||
|
To: pkgMap["requests"],
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
From: pkgMap["charset-normalizer"],
|
||||||
|
To: pkgMap["requests"],
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
From: pkgMap["urllib3"],
|
||||||
|
To: pkgMap["requests"],
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
From: pkgMap["idna"],
|
||||||
|
To: pkgMap["requests"],
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgtest.TestFileParser(t, fixture, parsePdmLock, expectedPkgs, expectedRelationships)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_corruptPdmLock(t *testing.T) {
|
||||||
|
pkgtest.NewCatalogTester().
|
||||||
|
FromFile(t, "test-fixtures/glob-paths/src/pdm.lock").
|
||||||
|
WithError().
|
||||||
|
TestParser(t, parsePdmLock)
|
||||||
|
}
|
||||||
1
syft/pkg/cataloger/python/test-fixtures/glob-paths/src/pdm.lock
generated
Normal file
1
syft/pkg/cataloger/python/test-fixtures/glob-paths/src/pdm.lock
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
bogus
|
||||||
137
syft/pkg/cataloger/python/test-fixtures/pdm-lock/pdm.lock
generated
Normal file
137
syft/pkg/cataloger/python/test-fixtures/pdm-lock/pdm.lock
generated
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
# This file is @generated by PDM.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
groups = ["default", "security", "tests"]
|
||||||
|
strategy = ["inherit_metadata", "static_urls"]
|
||||||
|
lock_version = "4.5.0"
|
||||||
|
content_hash = "sha256:2584886ac58a0ae70aa36bc0318b62c3e2c89acc9c21ebb9aee74147c0a9dc06"
|
||||||
|
|
||||||
|
[[metadata.targets]]
|
||||||
|
requires_python = ">=3.3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "certifi"
|
||||||
|
version = "2025.1.31"
|
||||||
|
requires_python = ">=3.6"
|
||||||
|
summary = "Python package for providing Mozilla's CA Bundle."
|
||||||
|
groups = ["security"]
|
||||||
|
marker = "python_version >= \"3.6\""
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chardet"
|
||||||
|
version = "3.0.4"
|
||||||
|
summary = "Universal encoding detector for Python 2 and 3"
|
||||||
|
groups = ["default"]
|
||||||
|
marker = "os_name == \"nt\""
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "charset-normalizer"
|
||||||
|
version = "2.0.12"
|
||||||
|
requires_python = ">=3.5.0"
|
||||||
|
summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||||
|
groups = ["security"]
|
||||||
|
marker = "python_version >= \"3.6\""
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/06/b3/24afc8868eba069a7f03650ac750a778862dc34941a4bebeb58706715726/charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/56/31/7bcaf657fafb3c6db8c787a865434290b726653c912085fbd371e9b92e1c/charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.3.9"
|
||||||
|
summary = "Cross-platform colored terminal text."
|
||||||
|
groups = ["tests"]
|
||||||
|
marker = "sys_platform == \"win32\""
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/db/c8/7dcf9dbcb22429512708fe3a547f8b6101c0d02137acbd892505aee57adf/colorama-0.3.9-py2.py3-none-any.whl", hash = "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/e6/76/257b53926889e2835355d74fec73d82662100135293e17d382e2b74d1669/colorama-0.3.9.tar.gz", hash = "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "2.7"
|
||||||
|
summary = "Internationalized Domain Names in Applications (IDNA)"
|
||||||
|
groups = ["default", "security"]
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/4b/2a/0276479a4b3caeb8a8c1af2f8e4355746a97fab05a372e4a2c6a6b876165/idna-2.7-py2.py3-none-any.whl", hash = "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/65/c4/80f97e9c9628f3cac9b98bfca0402ede54e0563b56482e3e6e45c43c4935/idna-2.7.tar.gz", hash = "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "py"
|
||||||
|
version = "1.4.34"
|
||||||
|
summary = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||||
|
groups = ["tests"]
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/53/67/9620edf7803ab867b175e4fd23c7b8bd8eba11cb761514dcd2e726ef07da/py-1.4.34-py2.py3-none-any.whl", hash = "sha256:2ccb79b01769d99115aa600d7eed99f524bf752bba8f041dc1c184853514655a"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/68/35/58572278f1c097b403879c1e9369069633d1cbad5239b9057944bb764782/py-1.4.34.tar.gz", hash = "sha256:0f2d585d22050e90c7d293b6451c83db097df77871974d90efd5a30dc12fcde3"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "3.2.5"
|
||||||
|
summary = "pytest: simple powerful testing with Python"
|
||||||
|
groups = ["tests"]
|
||||||
|
dependencies = [
|
||||||
|
"argparse; python_version == \"2.6\"",
|
||||||
|
"colorama; sys_platform == \"win32\"",
|
||||||
|
"ordereddict; python_version == \"2.6\"",
|
||||||
|
"py>=1.4.33",
|
||||||
|
"setuptools",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/1f/f8/8cd74c16952163ce0db0bd95fdd8810cbf093c08be00e6e665ebf0dc3138/pytest-3.2.5.tar.gz", hash = "sha256:6d5bd4f7113b444c55a3bbb5c738a3dd80d43563d063fc42dcb0aaefbdd78b81"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/ef/41/d8a61f1b2ba308e96b36106e95024977e30129355fd12087f23e4b9852a1/pytest-3.2.5-py2.py3-none-any.whl", hash = "sha256:241d7e7798d79192a123ceaf64c602b4d233eacf6d6e42ae27caa97f498b7dc6"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests"
|
||||||
|
version = "2.27.1"
|
||||||
|
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||||
|
summary = "Python HTTP for Humans."
|
||||||
|
groups = ["security"]
|
||||||
|
marker = "python_version >= \"3.6\""
|
||||||
|
dependencies = [
|
||||||
|
"certifi>=2017.4.17",
|
||||||
|
"chardet<5,>=3.0.2; python_version < \"3\"",
|
||||||
|
"charset-normalizer~=2.0.0; python_version >= \"3\"",
|
||||||
|
"idna<3,>=2.5; python_version < \"3\"",
|
||||||
|
"idna<4,>=2.5; python_version >= \"3\"",
|
||||||
|
"urllib3<1.27,>=1.21.1",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/2d/61/08076519c80041bc0ffa1a8af0cbd3bf3e2b62af10435d269a9d0f40564d/requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/60/f3/26ff3767f099b73e0efa138a9998da67890793bfa475d8278f84a30fec77/requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "setuptools"
|
||||||
|
version = "39.2.0"
|
||||||
|
requires_python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*"
|
||||||
|
summary = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||||
|
groups = ["tests"]
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/1a/04/d6f1159feaccdfc508517dba1929eb93a2854de729fa68da9d5c6b48fa00/setuptools-39.2.0.zip", hash = "sha256:f7cddbb5f5c640311eb00eab6e849f7701fa70bf6a183fc8a2c33dd1d1672fb2"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/7f/e1/820d941153923aac1d49d7fc37e17b6e73bfbd2904959fffbad77900cf92/setuptools-39.2.0-py2.py3-none-any.whl", hash = "sha256:8fca9275c89964f13da985c3656cb00ba029d7f3916b37990927ffdf264e7926"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urllib3"
|
||||||
|
version = "1.26.20"
|
||||||
|
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
||||||
|
summary = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
|
groups = ["security"]
|
||||||
|
marker = "python_version >= \"3.6\""
|
||||||
|
files = [
|
||||||
|
{url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"},
|
||||||
|
{url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"},
|
||||||
|
]
|
||||||
@ -9,8 +9,6 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
const cargoAuditBinaryCatalogerName = "cargo-auditable-binary-cataloger"
|
|
||||||
|
|
||||||
// NewCargoLockCataloger returns a new Rust Cargo lock file cataloger object.
|
// NewCargoLockCataloger returns a new Rust Cargo lock file cataloger object.
|
||||||
func NewCargoLockCataloger() pkg.Cataloger {
|
func NewCargoLockCataloger() pkg.Cataloger {
|
||||||
return generic.NewCataloger("rust-cargo-lock-cataloger").
|
return generic.NewCataloger("rust-cargo-lock-cataloger").
|
||||||
@ -20,6 +18,6 @@ func NewCargoLockCataloger() pkg.Cataloger {
|
|||||||
// NewAuditBinaryCataloger returns a new Rust auditable binary cataloger object that can detect dependencies
|
// NewAuditBinaryCataloger returns a new Rust auditable binary cataloger object that can detect dependencies
|
||||||
// in binaries produced with https://github.com/Shnatsel/rust-audit
|
// in binaries produced with https://github.com/Shnatsel/rust-audit
|
||||||
func NewAuditBinaryCataloger() pkg.Cataloger {
|
func NewAuditBinaryCataloger() pkg.Cataloger {
|
||||||
return generic.NewCataloger(cargoAuditBinaryCatalogerName).
|
return generic.NewCataloger("cargo-auditable-binary-cataloger").
|
||||||
WithParserByMimeTypes(parseAuditBinary, mimetype.ExecutableMIMETypeSet.List()...)
|
WithParserByMimeTypes(parseAuditBinary, mimetype.ExecutableMIMETypeSet.List()...)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,6 @@ func newPackageFromAudit(dep *rustaudit.Package, locations ...file.Location) pkg
|
|||||||
Language: pkg.Rust,
|
Language: pkg.Rust,
|
||||||
Type: pkg.RustPkg,
|
Type: pkg.RustPkg,
|
||||||
Locations: file.NewLocationSet(locations...),
|
Locations: file.NewLocationSet(locations...),
|
||||||
FoundBy: cargoAuditBinaryCatalogerName,
|
|
||||||
Metadata: pkg.RustBinaryAuditEntry{
|
Metadata: pkg.RustBinaryAuditEntry{
|
||||||
Name: dep.Name,
|
Name: dep.Name,
|
||||||
Version: dep.Version,
|
Version: dep.Version,
|
||||||
|
|||||||
@ -79,6 +79,16 @@ func (m PythonPackage) OwnedFiles() (result []string) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PythonPdmLockEntry represents a single package entry within a pdm.lock file.
|
||||||
|
type PythonPdmLockEntry struct {
|
||||||
|
// Summary provides a description of the package
|
||||||
|
Summary string `mapstructure:"summary" json:"summary" toml:"summary"`
|
||||||
|
// Files are the package files with their paths and hash digests
|
||||||
|
Files []PythonFileRecord `mapstructure:"files" json:"files" toml:"files"`
|
||||||
|
// Dependencies are the dependency specifications, without environment qualifiers
|
||||||
|
Dependencies []string `mapstructure:"dependencies" json:"dependencies" toml:"dependencies"`
|
||||||
|
}
|
||||||
|
|
||||||
// PythonPipfileLockEntry represents a single package entry within a Pipfile.lock file.
|
// PythonPipfileLockEntry represents a single package entry within a Pipfile.lock file.
|
||||||
type PythonPipfileLockEntry struct {
|
type PythonPipfileLockEntry struct {
|
||||||
// Hashes are the package file hash values in the format "algorithm:digest" for integrity verification.
|
// Hashes are the package file hash values in the format "algorithm:digest" for integrity verification.
|
||||||
|
|||||||
@ -231,11 +231,14 @@ func fileAnalysisPath(path string, skipExtractArchive bool) (string, func() erro
|
|||||||
// unarchived.
|
// unarchived.
|
||||||
envelopedUnarchiver, err := archiver.ByExtension(path)
|
envelopedUnarchiver, err := archiver.ByExtension(path)
|
||||||
if unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver); err == nil && ok {
|
if unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver); err == nil && ok {
|
||||||
if tar, ok := unarchiver.(*archiver.Tar); ok {
|
// when tar/zip files are extracted, if there are multiple entries at the same
|
||||||
// when tar files are extracted, if there are multiple entries at the same
|
// location, the last entry wins
|
||||||
// location, the last entry wins
|
// NOTE: this currently does not display any messages if an overwrite happens
|
||||||
// NOTE: this currently does not display any messages if an overwrite happens
|
switch v := unarchiver.(type) {
|
||||||
tar.OverwriteExisting = true
|
case *archiver.Tar:
|
||||||
|
v.OverwriteExisting = true
|
||||||
|
case *archiver.Zip:
|
||||||
|
v.OverwriteExisting = true
|
||||||
}
|
}
|
||||||
|
|
||||||
analysisPath, cleanupFn, err = unarchiveToTmp(path, unarchiver)
|
analysisPath, cleanupFn, err = unarchiveToTmp(path, unarchiver)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user