mirror of
https://github.com/anchore/syft.git
synced 2026-10-13 06:37:22 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
244b797a19 | ||
|
|
95176d7e0c | ||
|
|
5a7bab972c | ||
|
|
b69259534d | ||
|
|
44422853be | ||
|
|
cc731c7b19 | ||
|
|
5d156b8241 | ||
|
|
05715489c4 | ||
|
|
661d256b85 | ||
|
|
dd30c99bc2 | ||
|
|
16ebcb2455 | ||
|
|
305838582b | ||
|
|
a260fb2774 | ||
|
|
f83cae35f2 | ||
|
|
0fed17f1c8 | ||
|
|
da44db92e9 | ||
|
|
4a499c946e | ||
|
|
99c28a94a4 | ||
|
|
f7ac4e98af | ||
|
|
394ec8d215 | ||
|
|
7845381331 | ||
|
|
7464079a09 | ||
|
|
8a574c9ed9 | ||
|
|
681d250fdc | ||
|
|
2022ffa0e5 |
@@ -33,7 +33,7 @@ jobs:
|
||||
OUTPUT="${OUTPUT//'%'/'%25'}" # URL encode all '%' characters
|
||||
OUTPUT="${OUTPUT//$'\n'/'%0A'}" # URL encode all '\n' characters
|
||||
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
|
||||
echo "::set-output name=result::$OUTPUT"
|
||||
echo "result=$OUTPUT" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
app_id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
- uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
go mod tidy
|
||||
|
||||
# export the version for use with create-pull-request
|
||||
echo "::set-output name=LATEST_VERSION::$LATEST_VERSION"
|
||||
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_OUTPUT
|
||||
id: latest-version
|
||||
|
||||
- uses: tibdex/github-app-token@v1
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
app_id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
- uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
|
||||
@@ -34,33 +34,35 @@ jobs:
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- name: Restore Java test-fixture cache
|
||||
id: unit-java-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: syft/pkg/cataloger/java/test-fixtures/java-builds/packages
|
||||
key: ${{ runner.os }}-unit-java-cache-${{ hashFiles( 'syft/pkg/cataloger/java/test-fixtures/java-builds/packages.fingerprint' ) }}
|
||||
|
||||
- name: Restore RPM test-fixture cache
|
||||
id: unit-rpm-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: syft/pkg/cataloger/rpm/test-fixtures/rpms
|
||||
key: ${{ runner.os }}-unit-rpm-cache-${{ hashFiles( 'syft/pkg/cataloger/rpm/test-fixtures/rpms.fingerprint' ) }}
|
||||
|
||||
- name: Restore go binary test-fixture cache
|
||||
id: unit-go-binary-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: syft/pkg/cataloger/golang/test-fixtures/archs/binaries
|
||||
key: ${{ runner.os }}-unit-go-binaries-cache-${{ hashFiles( 'syft/pkg/cataloger/golang/test-fixtures/archs/binaries.fingerprint' ) }}
|
||||
|
||||
- name: Restore binary cataloger test-fixture cache
|
||||
id: unit-binary-cataloger-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: syft/pkg/cataloger/binary/test-fixtures/classifiers/dynamic
|
||||
key: ${{ runner.os }}-unit-binary-cataloger-cache-${{ hashFiles( 'syft/pkg/cataloger/binary/test-fixtures/cache.fingerprint' ) }}
|
||||
|
||||
- name: Restore Kernel test-fixture cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: syft/pkg/cataloger/kernel/test-fixtures/cache
|
||||
key: ${{ runner.os }}-unit-kernel-cache-${{ hashFiles( 'syft/pkg/cataloger/kernel/test-fixtures/cache.fingerprint' ) }}
|
||||
|
||||
- name: Run unit tests
|
||||
run: make unit
|
||||
|
||||
|
||||
+10
-2
@@ -15,7 +15,7 @@ After cloning the following step can help you get setup:
|
||||
- this command `go run cmd/syft/main.go alpine:latest` will compile and run syft against `alpine:latest`
|
||||
5. view the README or syft help output for more output options
|
||||
|
||||
The main make tasks for common static analysis and testing are `lint`, `lint-fix`, `unit`, `integration`, and `cli`.
|
||||
The main make tasks for common static analysis and testing are `lint`, `format`, `lint-fix`, `unit`, `integration`, and `cli`.
|
||||
|
||||
See `make help` for all the current make tasks.
|
||||
|
||||
@@ -119,7 +119,15 @@ sequenceDiagram
|
||||
Catalogers are the way in which syft is able to identify and construct packages given some amount of source metadata.
|
||||
For example, Syft can locate and process `package-lock.json` files when performing filesystem scans.
|
||||
See: [how to specify file globs](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/javascript/cataloger.go#L16-L21)
|
||||
and an implementation of the [package-lock.json parser](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/javascript/cataloger.go#L16-L21) fora quick review.
|
||||
and an implementation of the [package-lock.json parser](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/javascript/cataloger.go#L16-L21) for a quick review.
|
||||
|
||||
From a high level catalogers have the following properties:
|
||||
|
||||
- They are independent from one another. The java cataloger has no idea of the processes, assumptions, or results of the python cataloger, for example.
|
||||
|
||||
- They do not know what source is being analyzed. Are we analyzing a local directory? an image? if so, the squashed representation or all layers? The catalogers do not know the answers to these questions. Only that there is an interface to query for file paths and contents from an underlying "source" being scanned.
|
||||
|
||||
- Packages created by the cataloger should not be mutated after they are created. There is one exception made for adding CPEs to a package after the cataloging phase, but that will most likely be moved back into the cataloger in the future.
|
||||
|
||||
#### Building a new Cataloger
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ GOLANGCILINT_VERSION := v1.52.2
|
||||
GOSIMPORTS_VERSION := v0.3.8
|
||||
BOUNCER_VERSION := v0.4.0
|
||||
CHRONICLE_VERSION := v0.6.0
|
||||
GORELEASER_VERSION := v1.16.2
|
||||
GORELEASER_VERSION := v1.17.1
|
||||
YAJSV_VERSION := v1.4.1
|
||||
COSIGN_VERSION := v1.13.1
|
||||
QUILL_VERSION := v0.2.0
|
||||
@@ -118,14 +118,18 @@ lint: ## Run gofmt + golangci lint checks
|
||||
$(eval MALFORMED_FILENAMES := $(shell find . | grep -e ':'))
|
||||
@bash -c "[[ '$(MALFORMED_FILENAMES)' == '' ]] || (printf '\nfound unsupported filename characters:\n$(MALFORMED_FILENAMES)\n\n' && false)"
|
||||
|
||||
.PHONY: lint-fix
|
||||
lint-fix: ## Auto-format all source code + run golangci lint fixers
|
||||
$(call title,Running lint fixers)
|
||||
.PHONY: format
|
||||
format: ## Auto-format all source code
|
||||
$(call title,Running formatters)
|
||||
gofmt -w -s .
|
||||
$(GOIMPORTS_CMD) -w .
|
||||
$(LINT_CMD) --fix
|
||||
go mod tidy
|
||||
|
||||
.PHONY: lint-fix
|
||||
lint-fix: format ## Auto-format all source code + run golangci lint fixers
|
||||
$(call title,Running lint fixers)
|
||||
$(LINT_CMD) --fix
|
||||
|
||||
.PHONY: check-licenses
|
||||
check-licenses: ## Ensure transitive dependencies are compliant with the current license policy
|
||||
$(call title,Checking for license compliance)
|
||||
@@ -205,6 +209,10 @@ fingerprints:
|
||||
cd syft/pkg/cataloger/rpm/test-fixtures && \
|
||||
make rpms.fingerprint
|
||||
|
||||
# for Kernel test fixtures
|
||||
cd syft/pkg/cataloger/kernel/test-fixtures && \
|
||||
make cache.fingerprint
|
||||
|
||||
# for INSTALL integration test fixtures
|
||||
cd test/install && \
|
||||
make cache.fingerprint
|
||||
|
||||
@@ -42,9 +42,12 @@ For commercial support options with Syft or Grype, please [contact Anchore](http
|
||||
- Erlang (rebar3)
|
||||
- Go (go.mod, Go binaries)
|
||||
- Haskell (cabal, stack)
|
||||
- Java (jar, ear, war, par, sar, native-image)
|
||||
- Java (jar, ear, war, par, sar, nar, native-image)
|
||||
- JavaScript (npm, yarn)
|
||||
- Jenkins Plugins (jpi, hpi)
|
||||
- Linux kernel archives (vmlinz)
|
||||
- Linux kernel modules (ko)
|
||||
- Nix (outputs in /nix/store)
|
||||
- PHP (composer)
|
||||
- Python (wheel, egg, poetry, requirements.txt)
|
||||
- Red Hat (rpm)
|
||||
@@ -512,6 +515,25 @@ golang:
|
||||
# SYFT_GOLANG_LOCAL_MOD_CACHE_DIR env var
|
||||
local-mod-cache-dir: ""
|
||||
|
||||
# search for go package licences by retrieving the package from a network proxy
|
||||
# SYFT_GOLANG_SEARCH_REMOTE_LICENSES env var
|
||||
search-remote-licenses: false
|
||||
|
||||
# remote proxy to use when retrieving go packages from the network,
|
||||
# if unset this defaults to $GOPROXY followed by https://proxy.golang.org
|
||||
# SYFT_GOLANG_PROXY env var
|
||||
proxy: ""
|
||||
|
||||
# specifies packages which should not be fetched by proxy
|
||||
# if unset this defaults to $GONOPROXY
|
||||
# SYFT_GOLANG_NOPROXY env var
|
||||
no-proxy: ""
|
||||
|
||||
linux-kernel:
|
||||
# whether to catalog linux kernel modules found within lib/modules/** directories
|
||||
# SYFT_LINUX_KERNEL_CATALOG_MODULES env var
|
||||
catalog-modules: true
|
||||
|
||||
# cataloging file contents is exposed through the power-user subcommand
|
||||
file-contents:
|
||||
cataloger:
|
||||
|
||||
@@ -31,9 +31,9 @@ require (
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e
|
||||
github.com/sergi/go-diff v1.3.1
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spdx/tools-golang v0.5.0-rc1
|
||||
github.com/spdx/tools-golang v0.5.0
|
||||
github.com/spf13/afero v1.9.5
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.15.0
|
||||
github.com/stretchr/testify v1.8.2
|
||||
@@ -42,9 +42,9 @@ require (
|
||||
github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5
|
||||
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
golang.org/x/mod v0.9.0
|
||||
golang.org/x/net v0.8.0
|
||||
golang.org/x/term v0.6.0
|
||||
golang.org/x/mod v0.10.0
|
||||
golang.org/x/net v0.9.0
|
||||
golang.org/x/term v0.7.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
@@ -52,8 +52,11 @@ require (
|
||||
github.com/CycloneDX/cyclonedx-go v0.7.1-0.20221222100750-41a1ac565cce
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8
|
||||
github.com/anchore/stereoscope v0.0.0-20230323161519-d7551b7f46f5
|
||||
github.com/docker/docker v23.0.2+incompatible
|
||||
github.com/anchore/stereoscope v0.0.0-20230406143206-e95d60a265e3
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
|
||||
github.com/docker/docker v23.0.3+incompatible
|
||||
github.com/go-git/go-billy/v5 v5.4.1
|
||||
github.com/go-git/go-git/v5 v5.6.1
|
||||
github.com/google/go-containerregistry v0.14.0
|
||||
github.com/google/licensecheck v0.3.1
|
||||
github.com/invopop/jsonschema v0.7.0
|
||||
@@ -70,8 +73,11 @@ require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||
github.com/becheran/wildmatch-go v1.0.0 // indirect
|
||||
github.com/cloudflare/circl v1.1.0 // indirect
|
||||
github.com/containerd/containerd v1.6.18 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
@@ -81,8 +87,10 @@ require (
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-restruct/restruct v1.2.0-alpha // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
@@ -91,9 +99,11 @@ require (
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.16.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 // indirect
|
||||
@@ -108,11 +118,13 @@ require (
|
||||
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/skeema/knownhosts v1.1.0 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
@@ -122,19 +134,21 @@ require (
|
||||
github.com/therootcompany/xz v1.0.1 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/vbatts/tar-split v0.11.2 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect
|
||||
google.golang.org/grpc v1.52.0 // indirect
|
||||
google.golang.org/protobuf v1.29.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
lukechampine.com/uint128 v1.1.1 // indirect
|
||||
modernc.org/cc/v3 v3.36.0 // indirect
|
||||
modernc.org/ccgo/v3 v3.16.6 // indirect
|
||||
@@ -152,7 +166,7 @@ require (
|
||||
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
golang.org/x/crypto v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.6.0 // indirect
|
||||
)
|
||||
|
||||
retract (
|
||||
|
||||
@@ -65,13 +65,18 @@ github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7Y
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
|
||||
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/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
|
||||
github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY=
|
||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
||||
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@@ -90,18 +95,22 @@ github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZV
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501 h1:AV7qjwMcM4r8wFhJq3jLRztew3ywIyPTRapl2T1s9o8=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
|
||||
github.com/anchore/stereoscope v0.0.0-20230323161519-d7551b7f46f5 h1:2I4m/L4INVVyv0yBRuCadwxM+nuJoaKj9iBNPyXbSO4=
|
||||
github.com/anchore/stereoscope v0.0.0-20230323161519-d7551b7f46f5/go.mod h1:IihP/SUVHP94PBwIP2bepOB/c0MVadcII7lxo13Ijzs=
|
||||
github.com/anchore/stereoscope v0.0.0-20230406143206-e95d60a265e3 h1:F662TNGcpBfB1ZmCJJUot4EBHGxCKvTPvub01qaWxX0=
|
||||
github.com/anchore/stereoscope v0.0.0-20230406143206-e95d60a265e3/go.mod h1:u44RadbOJB103GwtYzJ2Kdad9J+SmZMW98jCYBJkSzs=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/becheran/wildmatch-go v1.0.0 h1:mE3dGGkTmpKtT4Z+88t8RStG40yN9T+kFEGj2PZFSzA=
|
||||
github.com/becheran/wildmatch-go v1.0.0/go.mod h1:gbMvj0NtVdJ15Mg/mH9uxk2R1QCistMyU7d9KFzroX4=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
@@ -111,6 +120,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
@@ -122,6 +132,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY=
|
||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@@ -141,17 +153,20 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da h1:ZOjWpVsFZ06eIhnh4mkaceTiVoktdU67+M7KDHJ268M=
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||
github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM=
|
||||
github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v23.0.2+incompatible h1:q81C2qQ/EhPm8COZMUGOQYh4qLv4Xu6CXELJ3WK/mlU=
|
||||
github.com/docker/docker v23.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho=
|
||||
github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
@@ -164,6 +179,8 @@ github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdf
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
@@ -190,6 +207,17 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS
|
||||
github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0FnbhiOsEro=
|
||||
github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
|
||||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
|
||||
github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
|
||||
github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -258,7 +286,6 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-containerregistry v0.14.0 h1:z58vMqHxuwvAsVwvKEkmVBz2TlgBgH5k6koEXBtlYkw=
|
||||
@@ -342,14 +369,16 @@ github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy770So=
|
||||
github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
|
||||
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
@@ -362,6 +391,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
@@ -379,16 +410,20 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -437,6 +472,7 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -446,6 +482,7 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
|
||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
@@ -464,6 +501,8 @@ github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha
|
||||
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
|
||||
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -517,10 +556,12 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
|
||||
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
|
||||
github.com/spdx/tools-golang v0.5.0-rc1 h1:ooCSe48QatlidqEFd+nSI308tyeNTR6NJvauUj3ApX8=
|
||||
github.com/spdx/tools-golang v0.5.0-rc1/go.mod h1:LI6onw172PdO57Ob/hgnLDD4Y2PMnroeNT3wO/2WJJI=
|
||||
github.com/spdx/tools-golang v0.5.0 h1:/fqihV2Jna7fmow65dHpgKNsilgLK7ICpd2tkCnPEyY=
|
||||
github.com/spdx/tools-golang v0.5.0/go.mod h1:kkGlrSXXfHwuSzHQZJRV3aKu9ZXCq/MSf2+xyiJH1lM=
|
||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||
@@ -530,8 +571,8 @@ github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
@@ -584,6 +625,8 @@ github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5 h1:lwgTsTy18
|
||||
github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA=
|
||||
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb h1:Yz6VVOcLuWLAHYlJzTw7JKnWxdV/WXpug2X0quEzRnY=
|
||||
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb/go.mod h1:nDi3BAC5nEbVbg+WSJDHLbjHv0ZToq8nMPA97XMxF3E=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@@ -617,6 +660,7 @@ go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
@@ -631,9 +675,14 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -674,8 +723,9 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -721,9 +771,13 @@ golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -798,6 +852,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -826,18 +881,26 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -848,8 +911,9 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -913,6 +977,7 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1076,11 +1141,15 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -1092,6 +1161,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
@@ -1139,6 +1209,7 @@ modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM=
|
||||
modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger"
|
||||
golangCataloger "github.com/anchore/syft/syft/pkg/cataloger/golang"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -50,6 +51,7 @@ type Application struct {
|
||||
Catalogers []string `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
|
||||
Package pkg `yaml:"package" json:"package" mapstructure:"package"`
|
||||
Golang golang `yaml:"golang" json:"golang" mapstructure:"golang"`
|
||||
LinuxKernel linuxKernel `yaml:"linux-kernel" json:"linux-kernel" mapstructure:"linux-kernel"`
|
||||
Attest attest `yaml:"attest" json:"attest" mapstructure:"attest"`
|
||||
FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
|
||||
FileClassification fileClassification `yaml:"file-classification" json:"file-classification" mapstructure:"file-classification"`
|
||||
@@ -72,9 +74,14 @@ func (cfg Application) ToCatalogerConfig() cataloger.Config {
|
||||
},
|
||||
Catalogers: cfg.Catalogers,
|
||||
Parallelism: cfg.Parallelism,
|
||||
Golang: golangCataloger.GoCatalogerOpts{
|
||||
SearchLocalModCacheLicenses: cfg.Golang.SearchLocalModCacheLicenses,
|
||||
LocalModCacheDir: cfg.Golang.LocalModCacheDir,
|
||||
Golang: golangCataloger.NewGoCatalogerOpts().
|
||||
WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses).
|
||||
WithLocalModCacheDir(cfg.Golang.LocalModCacheDir).
|
||||
WithSearchRemoteLicenses(cfg.Golang.SearchRemoteLicenses).
|
||||
WithProxy(cfg.Golang.Proxy).
|
||||
WithNoProxy(cfg.Golang.NoProxy),
|
||||
LinuxKernel: kernel.LinuxCatalogerConfig{
|
||||
CatalogModules: cfg.LinuxKernel.CatalogModules,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,15 @@ import "github.com/spf13/viper"
|
||||
type golang struct {
|
||||
SearchLocalModCacheLicenses bool `json:"search-local-mod-cache-licenses" yaml:"search-local-mod-cache-licenses" mapstructure:"search-local-mod-cache-licenses"`
|
||||
LocalModCacheDir string `json:"local-mod-cache-dir" yaml:"local-mod-cache-dir" mapstructure:"local-mod-cache-dir"`
|
||||
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
|
||||
Proxy string `json:"proxy" yaml:"proxy" mapstructure:"proxy"`
|
||||
NoProxy string `json:"no-proxy" yaml:"no-proxy" mapstructure:"no-proxy"`
|
||||
}
|
||||
|
||||
func (cfg golang) loadDefaultValues(v *viper.Viper) {
|
||||
v.SetDefault("golang.search-local-mod-cache-licenses", false)
|
||||
v.SetDefault("golang.local-mod-cache-dir", "")
|
||||
v.SetDefault("golang.search-remote-licenses", false)
|
||||
v.SetDefault("golang.proxy", "")
|
||||
v.SetDefault("golang.no-proxy", "")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package config
|
||||
|
||||
import "github.com/spf13/viper"
|
||||
|
||||
type linuxKernel struct {
|
||||
CatalogModules bool `json:"catalog-modules" yaml:"catalog-modules" mapstructure:"catalog-modules"`
|
||||
}
|
||||
|
||||
func (cfg linuxKernel) loadDefaultValues(v *viper.Viper) {
|
||||
v.SetDefault("linux-kernel.catalog-modules", true)
|
||||
}
|
||||
@@ -6,5 +6,5 @@ const (
|
||||
|
||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||
JSONSchemaVersion = "7.0.1"
|
||||
JSONSchemaVersion = "7.1.4"
|
||||
)
|
||||
|
||||
@@ -45,6 +45,9 @@ type artifactMetadataContainer struct {
|
||||
Hackage pkg.HackageMetadata
|
||||
Java pkg.JavaMetadata
|
||||
KbPackage pkg.KbPackageMetadata
|
||||
LinuxKernel pkg.LinuxKernelMetadata
|
||||
LinuxKernelModule pkg.LinuxKernelModuleMetadata
|
||||
Nix pkg.NixStoreMetadata
|
||||
NpmPackage pkg.NpmPackageJSONMetadata
|
||||
NpmPackageLock pkg.NpmPackageLockJSONMetadata
|
||||
MixLock pkg.MixLockMetadata
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,12 @@ const (
|
||||
// has been completed.
|
||||
OwnershipByFileOverlapRelationship RelationshipType = "ownership-by-file-overlap"
|
||||
|
||||
// EvidentByRelationship is a package-to-file relationship indicating the that existence of this package is evident
|
||||
// by the contents of a file. This does not necessarily mean that the package is contained within that file
|
||||
// or that it is described by it (either or both may be true). This does NOT map to an existing specific SPDX
|
||||
// relationship. Instead, this should be mapped to OTHER and the comment field be updated to show EVIDENT_BY.
|
||||
EvidentByRelationship RelationshipType = "evident-by"
|
||||
|
||||
// ContainsRelationship (supports any-to-any linkages) is a proxy for the SPDX 2.2 CONTAINS relationship.
|
||||
ContainsRelationship RelationshipType = "contains"
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
)
|
||||
|
||||
type CatalogerTask struct {
|
||||
prog *progress.Manual
|
||||
// Title
|
||||
Title string
|
||||
// TitleOnCompletion a string to use as title when completed
|
||||
TitleOnCompletion string
|
||||
// SubStatus indicates this progress should be rendered as a sub-item
|
||||
SubStatus bool
|
||||
// RemoveOnCompletion indicates this progress line will be removed when completed
|
||||
RemoveOnCompletion bool
|
||||
// value is the value to display -- not public as SetValue needs to be called to initialize this progress
|
||||
value string
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) init() {
|
||||
e.prog = progress.NewManual(-1)
|
||||
|
||||
bus.Publish(partybus.Event{
|
||||
Type: CatalogerTaskStarted,
|
||||
Source: e,
|
||||
})
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) SetCompleted() {
|
||||
if e.prog != nil {
|
||||
e.prog.SetCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) SetValue(value string) {
|
||||
if e.prog == nil {
|
||||
e.init()
|
||||
}
|
||||
e.value = value
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) GetValue() string {
|
||||
return e.value
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) GetMonitor() *progress.Manual {
|
||||
return e.prog
|
||||
}
|
||||
@@ -34,4 +34,7 @@ const (
|
||||
|
||||
// AttestationStarted is a partybus event that occurs when starting an SBOM attestation process
|
||||
AttestationStarted partybus.EventType = "syft-attestation-started-event"
|
||||
|
||||
// CatalogerTaskStarted is a partybus event that occurs when starting a task within a cataloger
|
||||
CatalogerTaskStarted partybus.EventType = "syft-cataloger-task-started"
|
||||
)
|
||||
|
||||
@@ -111,6 +111,19 @@ func ParseFileIndexingStarted(e partybus.Event) (string, progress.StagedProgress
|
||||
return path, prog, nil
|
||||
}
|
||||
|
||||
func ParseCatalogerTaskStarted(e partybus.Event) (*event.CatalogerTask, error) {
|
||||
if err := checkEventType(e.Type, event.CatalogerTaskStarted); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
source, ok := e.Source.(*event.CatalogerTask)
|
||||
if !ok {
|
||||
return nil, newPayloadErr(e.Type, "Source", e.Source)
|
||||
}
|
||||
|
||||
return source, nil
|
||||
}
|
||||
|
||||
func ParseExit(e partybus.Event) (func() error, error) {
|
||||
if err := checkEventType(e.Type, event.Exit); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -29,7 +29,7 @@ func Test_encodeComponentProperties(t *testing.T) {
|
||||
input: pkg.Package{
|
||||
FoundBy: "cataloger",
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{Coordinates: source.Coordinates{RealPath: "test"}},
|
||||
source.NewLocationFromCoordinates(source.Coordinates{RealPath: "test"}),
|
||||
),
|
||||
Metadata: pkg.ApkMetadata{
|
||||
Package: "libc-utils",
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
//nolint:funlen
|
||||
func SourceInfo(p pkg.Package) string {
|
||||
answer := ""
|
||||
switch p.Type {
|
||||
@@ -45,6 +46,12 @@ func SourceInfo(p pkg.Package) string {
|
||||
answer = "acquired package info from cabal or stack manifest files"
|
||||
case pkg.HexPkg:
|
||||
answer = "acquired package info from rebar3 or mix manifest file"
|
||||
case pkg.LinuxKernelPkg:
|
||||
answer = "acquired package info from linux kernel archive"
|
||||
case pkg.LinuxKernelModulePkg:
|
||||
answer = "acquired package info from linux kernel module files"
|
||||
case pkg.NixPkg:
|
||||
answer = "acquired package info from nix store path"
|
||||
default:
|
||||
answer = "acquired package info from the following paths"
|
||||
}
|
||||
|
||||
@@ -199,6 +199,30 @@ func Test_SourceInfo(t *testing.T) {
|
||||
"from rebar3 or mix manifest file",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.LinuxKernelPkg,
|
||||
},
|
||||
expected: []string{
|
||||
"from linux kernel archive",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.LinuxKernelModulePkg,
|
||||
},
|
||||
expected: []string{
|
||||
"from linux kernel module files",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.NixPkg,
|
||||
},
|
||||
expected: []string{
|
||||
"from nix store path",
|
||||
},
|
||||
},
|
||||
}
|
||||
var pkgTypes []pkg.Type
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -408,6 +408,8 @@ func lookupRelationship(ty artifact.RelationshipType) (bool, RelationshipType, s
|
||||
return true, DependencyOfRelationship, ""
|
||||
case artifact.OwnershipByFileOverlapRelationship:
|
||||
return true, OtherRelationship, fmt.Sprintf("%s: indicates that the parent package claims ownership of a child package since the parent metadata indicates overlap with a location that a cataloger found the child package by", ty)
|
||||
case artifact.EvidentByRelationship:
|
||||
return true, OtherRelationship, fmt.Sprintf("%s: indicates the package's existence is evident by the given file", ty)
|
||||
}
|
||||
return false, "", ""
|
||||
}
|
||||
|
||||
@@ -209,6 +209,12 @@ func Test_lookupRelationship(t *testing.T) {
|
||||
ty: OtherRelationship,
|
||||
comment: "ownership-by-file-overlap: indicates that the parent package claims ownership of a child package since the parent metadata indicates overlap with a location that a cataloger found the child package by",
|
||||
},
|
||||
{
|
||||
input: artifact.EvidentByRelationship,
|
||||
exists: true,
|
||||
ty: OtherRelationship,
|
||||
comment: "evident-by: indicates the package's existence is evident by the given file",
|
||||
},
|
||||
{
|
||||
input: "made-up",
|
||||
exists: false,
|
||||
|
||||
@@ -176,9 +176,16 @@ func toSyftRelationships(spdxIDMap map[string]interface{}, doc *spdx.Document) [
|
||||
var to artifact.Identifiable
|
||||
var typ artifact.RelationshipType
|
||||
if toLocationOk {
|
||||
if r.Relationship == string(ContainsRelationship) {
|
||||
switch RelationshipType(r.Relationship) {
|
||||
case ContainsRelationship:
|
||||
typ = artifact.ContainsRelationship
|
||||
to = toLocation
|
||||
case OtherRelationship:
|
||||
// Encoding uses a specifically formatted comment...
|
||||
if strings.Index(r.RelationshipComment, string(artifact.EvidentByRelationship)) == 0 {
|
||||
typ = artifact.EvidentByRelationship
|
||||
to = toLocation
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch RelationshipType(r.Relationship) {
|
||||
@@ -188,7 +195,7 @@ func toSyftRelationships(spdxIDMap map[string]interface{}, doc *spdx.Document) [
|
||||
case OtherRelationship:
|
||||
// Encoding uses a specifically formatted comment...
|
||||
if strings.Index(r.RelationshipComment, string(artifact.OwnershipByFileOverlapRelationship)) == 0 {
|
||||
typ = artifact.DependencyOfRelationship
|
||||
typ = artifact.OwnershipByFileOverlapRelationship
|
||||
to = toPackage
|
||||
}
|
||||
}
|
||||
@@ -220,10 +227,8 @@ func toSyftCoordinates(f *spdx.File) source.Coordinates {
|
||||
}
|
||||
|
||||
func toSyftLocation(f *spdx.File) *source.Location {
|
||||
return &source.Location{
|
||||
Coordinates: toSyftCoordinates(f),
|
||||
VirtualPath: f.FileName,
|
||||
}
|
||||
l := source.NewVirtualLocationFromCoordinates(toSyftCoordinates(f), f.FileName)
|
||||
return &l
|
||||
}
|
||||
|
||||
func requireAndTrimPrefix(val interface{}, prefix string) string {
|
||||
|
||||
@@ -4,9 +4,11 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/spdx/tools-golang/spdx"
|
||||
"github.com/spdx/tools-golang/spdx/v2/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
@@ -307,3 +309,113 @@ func TestH1Digest(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_toSyftRelationships(t *testing.T) {
|
||||
type args struct {
|
||||
spdxIDMap map[string]interface{}
|
||||
doc *spdx.Document
|
||||
}
|
||||
|
||||
pkg1 := pkg.Package{
|
||||
Name: "github.com/googleapis/gnostic",
|
||||
Version: "v0.5.5",
|
||||
}
|
||||
pkg1.SetID()
|
||||
|
||||
pkg2 := pkg.Package{
|
||||
Name: "rfc3339",
|
||||
Version: "1.2",
|
||||
Type: pkg.RpmPkg,
|
||||
}
|
||||
pkg2.SetID()
|
||||
|
||||
pkg3 := pkg.Package{
|
||||
Name: "rfc3339",
|
||||
Version: "1.2",
|
||||
Type: pkg.PythonPkg,
|
||||
}
|
||||
pkg3.SetID()
|
||||
|
||||
loc1 := source.NewLocationFromCoordinates(source.Coordinates{
|
||||
RealPath: "/somewhere/real",
|
||||
FileSystemID: "abc",
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []artifact.Relationship
|
||||
}{
|
||||
{
|
||||
name: "evident-by relationship",
|
||||
args: args{
|
||||
spdxIDMap: map[string]interface{}{
|
||||
string(toSPDXID(pkg1)): &pkg1,
|
||||
string(toSPDXID(loc1)): &loc1,
|
||||
},
|
||||
doc: &spdx.Document{
|
||||
Relationships: []*spdx.Relationship{
|
||||
{
|
||||
RefA: common.DocElementID{
|
||||
ElementRefID: toSPDXID(pkg1),
|
||||
},
|
||||
RefB: common.DocElementID{
|
||||
ElementRefID: toSPDXID(loc1),
|
||||
},
|
||||
Relationship: spdx.RelationshipOther,
|
||||
RelationshipComment: "evident-by: indicates the package's existence is evident by the given file",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []artifact.Relationship{
|
||||
{
|
||||
From: pkg1,
|
||||
To: loc1,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ownership-by-file-overlap relationship",
|
||||
args: args{
|
||||
spdxIDMap: map[string]interface{}{
|
||||
string(toSPDXID(pkg2)): &pkg2,
|
||||
string(toSPDXID(pkg3)): &pkg3,
|
||||
},
|
||||
doc: &spdx.Document{
|
||||
Relationships: []*spdx.Relationship{
|
||||
{
|
||||
RefA: common.DocElementID{
|
||||
ElementRefID: toSPDXID(pkg2),
|
||||
},
|
||||
RefB: common.DocElementID{
|
||||
ElementRefID: toSPDXID(pkg3),
|
||||
},
|
||||
Relationship: spdx.RelationshipOther,
|
||||
RelationshipComment: "ownership-by-file-overlap: indicates that the parent package claims ownership of a child package since the parent metadata indicates overlap with a location that a cataloger found the child package by",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []artifact.Relationship{
|
||||
{
|
||||
From: pkg2,
|
||||
To: pkg3,
|
||||
Type: artifact.OwnershipByFileOverlapRelationship,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
actual := toSyftRelationships(tt.args.spdxIDMap, tt.args.doc)
|
||||
require.Len(t, actual, len(tt.want))
|
||||
for i := range actual {
|
||||
require.Equal(t, tt.want[i].From.ID(), actual[i].From.ID())
|
||||
require.Equal(t, tt.want[i].To.ID(), actual[i].To.ID())
|
||||
require.Equal(t, tt.want[i].Type, actual[i].Type)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,36 +36,30 @@ func Test_toGithubModel(t *testing.T) {
|
||||
Name: "pkg-1",
|
||||
Version: "1.0.1",
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/usr/lib",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
},
|
||||
source.NewLocationFromCoordinates(source.Coordinates{
|
||||
RealPath: "/usr/lib",
|
||||
FileSystemID: "fsid-1",
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
Name: "pkg-2",
|
||||
Version: "2.0.2",
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/usr/lib",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
},
|
||||
source.NewLocationFromCoordinates(source.Coordinates{
|
||||
RealPath: "/usr/lib",
|
||||
FileSystemID: "fsid-1",
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
Name: "pkg-3",
|
||||
Version: "3.0.3",
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/etc",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
},
|
||||
source.NewLocationFromCoordinates(source.Coordinates{
|
||||
RealPath: "/etc",
|
||||
FileSystemID: "fsid-1",
|
||||
}),
|
||||
),
|
||||
},
|
||||
} {
|
||||
|
||||
@@ -53,11 +53,9 @@ func TestEncodeFullJSONDocument(t *testing.T) {
|
||||
Name: "package-1",
|
||||
Version: "1.0.1",
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/a/place/a",
|
||||
},
|
||||
},
|
||||
source.NewLocationFromCoordinates(source.Coordinates{
|
||||
RealPath: "/a/place/a",
|
||||
}),
|
||||
),
|
||||
Type: pkg.PythonPkg,
|
||||
FoundBy: "the-cataloger-1",
|
||||
@@ -79,11 +77,9 @@ func TestEncodeFullJSONDocument(t *testing.T) {
|
||||
Name: "package-2",
|
||||
Version: "2.0.1",
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/b/place/b",
|
||||
},
|
||||
},
|
||||
source.NewLocationFromCoordinates(source.Coordinates{
|
||||
RealPath: "/b/place/b",
|
||||
}),
|
||||
),
|
||||
Type: pkg.DebPkg,
|
||||
FoundBy: "the-cataloger-2",
|
||||
|
||||
@@ -20,4 +20,5 @@ type FileMetadataEntry struct {
|
||||
UserID int `json:"userID"`
|
||||
GroupID int `json:"groupID"`
|
||||
MIMEType string `json:"mimeType"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
@@ -21,16 +21,16 @@ type Package struct {
|
||||
|
||||
// PackageBasicData contains non-ambiguous values (type-wise) from pkg.Package.
|
||||
type PackageBasicData struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Type pkg.Type `json:"type"`
|
||||
FoundBy string `json:"foundBy"`
|
||||
Locations []source.Coordinates `json:"locations"`
|
||||
Licenses []string `json:"licenses"`
|
||||
Language pkg.Language `json:"language"`
|
||||
CPEs []string `json:"cpes"`
|
||||
PURL string `json:"purl"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Type pkg.Type `json:"type"`
|
||||
FoundBy string `json:"foundBy"`
|
||||
Locations []source.Location `json:"locations"`
|
||||
Licenses []string `json:"licenses"`
|
||||
Language pkg.Language `json:"language"`
|
||||
CPEs []string `json:"cpes"`
|
||||
PURL string `json:"purl"`
|
||||
}
|
||||
|
||||
// PackageCustomData contains ambiguous values (type-wise) from pkg.Package.
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "6.2.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-6.2.0.json"
|
||||
"version": "7.1.4",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-7.1.4.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@
|
||||
"type": "Directory",
|
||||
"userID": 0,
|
||||
"groupID": 0,
|
||||
"mimeType": ""
|
||||
"mimeType": "",
|
||||
"size": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -94,7 +95,8 @@
|
||||
"type": "RegularFile",
|
||||
"userID": 0,
|
||||
"groupID": 0,
|
||||
"mimeType": ""
|
||||
"mimeType": "",
|
||||
"size": 0
|
||||
},
|
||||
"contents": "the-contents",
|
||||
"digests": [
|
||||
@@ -115,7 +117,8 @@
|
||||
"linkDestination": "/c",
|
||||
"userID": 0,
|
||||
"groupID": 0,
|
||||
"mimeType": ""
|
||||
"mimeType": "",
|
||||
"size": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -128,7 +131,8 @@
|
||||
"type": "RegularFile",
|
||||
"userID": 1,
|
||||
"groupID": 2,
|
||||
"mimeType": ""
|
||||
"mimeType": "",
|
||||
"size": 0
|
||||
},
|
||||
"digests": [
|
||||
{
|
||||
@@ -185,7 +189,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "6.2.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-6.2.0.json"
|
||||
"version": "7.1.4",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-7.1.4.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "6.2.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-6.2.0.json"
|
||||
"version": "7.1.4",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-7.1.4.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ func toFileMetadataEntry(coordinates source.Coordinates, metadata *source.FileMe
|
||||
UserID: metadata.UserID,
|
||||
GroupID: metadata.GroupID,
|
||||
MIMEType: metadata.MIMEType,
|
||||
Size: metadata.Size,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,12 +196,6 @@ func toPackageModel(p pkg.Package) model.Package {
|
||||
licenses = p.Licenses
|
||||
}
|
||||
|
||||
locations := p.Locations.ToSlice()
|
||||
var coordinates = make([]source.Coordinates, len(locations))
|
||||
for i, l := range locations {
|
||||
coordinates[i] = l.Coordinates
|
||||
}
|
||||
|
||||
return model.Package{
|
||||
PackageBasicData: model.PackageBasicData{
|
||||
ID: string(p.ID()),
|
||||
@@ -208,7 +203,7 @@ func toPackageModel(p pkg.Package) model.Package {
|
||||
Version: p.Version,
|
||||
Type: p.Type,
|
||||
FoundBy: p.FoundBy,
|
||||
Locations: coordinates,
|
||||
Locations: p.Locations.ToSlice(),
|
||||
Licenses: licenses,
|
||||
Language: p.Language,
|
||||
CPEs: cpes,
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package syftjson
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/formats/syftjson/model"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -20,9 +24,13 @@ func toSyftModel(doc model.Document) (*sbom.SBOM, error) {
|
||||
|
||||
catalog := toSyftCatalog(doc.Artifacts, idAliases)
|
||||
|
||||
fileArtifacts := toSyftFiles(doc.Files)
|
||||
|
||||
return &sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
PackageCatalog: catalog,
|
||||
FileMetadata: fileArtifacts.FileMetadata,
|
||||
FileDigests: fileArtifacts.FileDigests,
|
||||
LinuxDistribution: toSyftLinuxRelease(doc.Distro),
|
||||
},
|
||||
Source: *toSyftSourceData(doc.Source),
|
||||
@@ -31,6 +39,72 @@ func toSyftModel(doc model.Document) (*sbom.SBOM, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toSyftFiles(files []model.File) sbom.Artifacts {
|
||||
ret := sbom.Artifacts{
|
||||
FileMetadata: make(map[source.Coordinates]source.FileMetadata),
|
||||
FileDigests: make(map[source.Coordinates][]file.Digest),
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
coord := f.Location
|
||||
if f.Metadata != nil {
|
||||
mode, err := strconv.ParseInt(strconv.Itoa(f.Metadata.Mode), 8, 64)
|
||||
if err != nil {
|
||||
log.Warnf("invalid mode found in file catalog @ location=%+v mode=%q: %+v", coord, f.Metadata.Mode, err)
|
||||
mode = 0
|
||||
}
|
||||
|
||||
fm := os.FileMode(mode)
|
||||
|
||||
ret.FileMetadata[coord] = source.FileMetadata{
|
||||
Path: coord.RealPath,
|
||||
LinkDestination: f.Metadata.LinkDestination,
|
||||
Size: f.Metadata.Size,
|
||||
UserID: f.Metadata.UserID,
|
||||
GroupID: f.Metadata.GroupID,
|
||||
Type: toSyftFileType(f.Metadata.Type),
|
||||
IsDir: fm.IsDir(),
|
||||
Mode: fm,
|
||||
MIMEType: f.Metadata.MIMEType,
|
||||
}
|
||||
}
|
||||
|
||||
for _, d := range f.Digests {
|
||||
ret.FileDigests[coord] = append(ret.FileDigests[coord], file.Digest{
|
||||
Algorithm: d.Algorithm,
|
||||
Value: d.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func toSyftFileType(ty string) stereoscopeFile.Type {
|
||||
switch ty {
|
||||
case "SymbolicLink":
|
||||
return stereoscopeFile.TypeSymLink
|
||||
case "HardLink":
|
||||
return stereoscopeFile.TypeHardLink
|
||||
case "Directory":
|
||||
return stereoscopeFile.TypeDirectory
|
||||
case "Socket":
|
||||
return stereoscopeFile.TypeSocket
|
||||
case "BlockDevice":
|
||||
return stereoscopeFile.TypeBlockDevice
|
||||
case "CharacterDevice":
|
||||
return stereoscopeFile.TypeCharacterDevice
|
||||
case "FIFONode":
|
||||
return stereoscopeFile.TypeFIFO
|
||||
case "RegularFile":
|
||||
return stereoscopeFile.TypeRegular
|
||||
case "IrregularFile":
|
||||
return stereoscopeFile.TypeIrregular
|
||||
default:
|
||||
return stereoscopeFile.TypeIrregular
|
||||
}
|
||||
}
|
||||
|
||||
func toSyftLinuxRelease(d model.LinuxRelease) *linux.Release {
|
||||
if cmp.Equal(d, model.LinuxRelease{}) {
|
||||
return nil
|
||||
@@ -117,7 +191,7 @@ func toSyftRelationship(idMap map[string]interface{}, relationship model.Relatio
|
||||
typ := artifact.RelationshipType(relationship.Type)
|
||||
|
||||
switch typ {
|
||||
case artifact.OwnershipByFileOverlapRelationship, artifact.ContainsRelationship, artifact.DependencyOfRelationship:
|
||||
case artifact.OwnershipByFileOverlapRelationship, artifact.ContainsRelationship, artifact.DependencyOfRelationship, artifact.EvidentByRelationship:
|
||||
default:
|
||||
if !strings.Contains(string(typ), "dependency-of") {
|
||||
log.Warnf("unknown relationship type: %s", typ)
|
||||
@@ -202,16 +276,11 @@ func toSyftPackage(p model.Package, idAliases map[string]string) pkg.Package {
|
||||
cpes = append(cpes, value)
|
||||
}
|
||||
|
||||
var locations = make([]source.Location, len(p.Locations))
|
||||
for i, c := range p.Locations {
|
||||
locations[i] = source.NewLocationFromCoordinates(c)
|
||||
}
|
||||
|
||||
out := pkg.Package{
|
||||
Name: p.Name,
|
||||
Version: p.Version,
|
||||
FoundBy: p.FoundBy,
|
||||
Locations: source.NewLocationSet(locations...),
|
||||
Locations: source.NewLocationSet(p.Locations...),
|
||||
Licenses: p.Licenses,
|
||||
Language: p.Language,
|
||||
Type: p.Type,
|
||||
|
||||
@@ -6,8 +6,11 @@ import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
stereoFile "github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/formats/syftjson/model"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
@@ -124,3 +127,104 @@ func Test_idsHaveChanged(t *testing.T) {
|
||||
assert.NotNil(t, to)
|
||||
assert.Equal(t, "pkg-2", to.Name)
|
||||
}
|
||||
|
||||
func Test_toSyftFiles(t *testing.T) {
|
||||
coord := source.Coordinates{
|
||||
RealPath: "/somerwhere/place",
|
||||
FileSystemID: "abc",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
files []model.File
|
||||
want sbom.Artifacts
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
files: []model.File{},
|
||||
want: sbom.Artifacts{
|
||||
FileMetadata: map[source.Coordinates]source.FileMetadata{},
|
||||
FileDigests: map[source.Coordinates][]file.Digest{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no metadata",
|
||||
files: []model.File{
|
||||
{
|
||||
ID: string(coord.ID()),
|
||||
Location: coord,
|
||||
Metadata: nil,
|
||||
Digests: []file.Digest{
|
||||
{
|
||||
Algorithm: "sha256",
|
||||
Value: "123",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: sbom.Artifacts{
|
||||
FileMetadata: map[source.Coordinates]source.FileMetadata{},
|
||||
FileDigests: map[source.Coordinates][]file.Digest{
|
||||
coord: {
|
||||
{
|
||||
Algorithm: "sha256",
|
||||
Value: "123",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single file",
|
||||
files: []model.File{
|
||||
{
|
||||
ID: string(coord.ID()),
|
||||
Location: coord,
|
||||
Metadata: &model.FileMetadataEntry{
|
||||
Mode: 777,
|
||||
Type: "RegularFile",
|
||||
LinkDestination: "",
|
||||
UserID: 42,
|
||||
GroupID: 32,
|
||||
MIMEType: "text/plain",
|
||||
Size: 92,
|
||||
},
|
||||
Digests: []file.Digest{
|
||||
{
|
||||
Algorithm: "sha256",
|
||||
Value: "123",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: sbom.Artifacts{
|
||||
FileMetadata: map[source.Coordinates]source.FileMetadata{
|
||||
coord: {
|
||||
Path: coord.RealPath,
|
||||
LinkDestination: "",
|
||||
Size: 92,
|
||||
UserID: 42,
|
||||
GroupID: 32,
|
||||
Type: stereoFile.TypeRegular,
|
||||
IsDir: false,
|
||||
Mode: 511, // 777 octal = 511 decimal
|
||||
MIMEType: "text/plain",
|
||||
},
|
||||
},
|
||||
FileDigests: map[source.Coordinates][]file.Digest{
|
||||
coord: {
|
||||
{
|
||||
Algorithm: "sha256",
|
||||
Value: "123",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, toSyftFiles(tt.files))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+16
-16
@@ -327,45 +327,45 @@ func TestCatalog_MergeRecords(t *testing.T) {
|
||||
{
|
||||
CPEs: []cpe.CPE{cpe.Must("cpe:2.3:a:package:1:1:*:*:*:*:*:*:*")},
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewVirtualLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/b/path",
|
||||
FileSystemID: "a",
|
||||
},
|
||||
VirtualPath: "/another/path",
|
||||
},
|
||||
"/another/path",
|
||||
),
|
||||
),
|
||||
Type: RpmPkg,
|
||||
},
|
||||
{
|
||||
CPEs: []cpe.CPE{cpe.Must("cpe:2.3:b:package:1:1:*:*:*:*:*:*:*")},
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewVirtualLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/b/path",
|
||||
FileSystemID: "b",
|
||||
},
|
||||
VirtualPath: "/another/path",
|
||||
},
|
||||
"/another/path",
|
||||
),
|
||||
),
|
||||
Type: RpmPkg,
|
||||
},
|
||||
},
|
||||
expectedLocations: []source.Location{
|
||||
{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewVirtualLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/b/path",
|
||||
FileSystemID: "a",
|
||||
},
|
||||
VirtualPath: "/another/path",
|
||||
},
|
||||
{
|
||||
Coordinates: source.Coordinates{
|
||||
"/another/path",
|
||||
),
|
||||
source.NewVirtualLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/b/path",
|
||||
FileSystemID: "b",
|
||||
},
|
||||
VirtualPath: "/another/path",
|
||||
},
|
||||
"/another/path",
|
||||
),
|
||||
},
|
||||
expectedCPECount: 2,
|
||||
},
|
||||
|
||||
@@ -70,7 +70,11 @@ func parseAlpmDB(resolver source.FileResolver, env *generic.Environment, reader
|
||||
}
|
||||
|
||||
return []pkg.Package{
|
||||
newPackage(*metadata, env.LinuxRelease, reader.Location),
|
||||
newPackage(
|
||||
*metadata,
|
||||
env.LinuxRelease,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ func parseApkDB(resolver source.FileResolver, env *generic.Environment, reader s
|
||||
|
||||
pkgs := make([]pkg.Package, 0, len(apks))
|
||||
for _, apk := range apks {
|
||||
pkgs = append(pkgs, newPackage(apk, r, reader.Location))
|
||||
pkgs = append(pkgs, newPackage(apk, r, reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)))
|
||||
}
|
||||
|
||||
return pkgs, discoverPackageDependencies(pkgs), nil
|
||||
|
||||
@@ -714,6 +714,18 @@ func Test_Cataloger_DefaultClassifiers_PositiveCases(t *testing.T) {
|
||||
Metadata: metadata("ruby-binary"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "positive-consul-1.15.2",
|
||||
fixtureDir: "test-fixtures/classifiers/dynamic/consul-1.15.2",
|
||||
expected: pkg.Package{
|
||||
Name: "consul",
|
||||
Version: "1.15.2",
|
||||
Type: "binary",
|
||||
PURL: "pkg:golang/github.com/hashicorp/consul@1.15.2",
|
||||
Locations: locations("consul"),
|
||||
Metadata: metadata("consul-binary"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -829,12 +841,12 @@ func match(classifier string, paths ...string) pkg.ClassifierMatch {
|
||||
}
|
||||
return pkg.ClassifierMatch{
|
||||
Classifier: classifier,
|
||||
Location: source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
Location: source.NewVirtualLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: realPath,
|
||||
},
|
||||
VirtualPath: virtualPath,
|
||||
},
|
||||
virtualPath,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"debug/pe"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
@@ -107,7 +106,13 @@ func fileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate stri
|
||||
}
|
||||
|
||||
matchMetadata := internal.MatchNamedCaptureGroups(tmplPattern, string(contents))
|
||||
return singlePackage(classifier, location, matchMetadata), nil
|
||||
|
||||
p := newPackage(classifier, location, matchMetadata)
|
||||
if p == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return []pkg.Package{*p}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +125,13 @@ func fileContentsVersionMatcher(pattern string) evidenceMatcher {
|
||||
}
|
||||
|
||||
matchMetadata := internal.MatchNamedCaptureGroups(pat, string(contents))
|
||||
return singlePackage(classifier, location, matchMetadata), nil
|
||||
|
||||
p := newPackage(classifier, location, matchMetadata)
|
||||
if p == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return []pkg.Package{*p}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,8 +152,8 @@ func sharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher evide
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, libraryLication := range locations {
|
||||
pkgs, err := sharedLibraryMatcher(resolver, classifier, libraryLication)
|
||||
for _, libraryLocation := range locations {
|
||||
pkgs, err := sharedLibraryMatcher(resolver, classifier, libraryLocation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -176,58 +187,6 @@ func mustPURL(purl string) packageurl.PackageURL {
|
||||
return p
|
||||
}
|
||||
|
||||
func singlePackage(classifier classifier, location source.Location, matchMetadata map[string]string) []pkg.Package {
|
||||
version, ok := matchMetadata["version"]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
update := matchMetadata["update"]
|
||||
|
||||
var cpes []cpe.CPE
|
||||
for _, c := range classifier.CPEs {
|
||||
c.Version = version
|
||||
c.Update = update
|
||||
cpes = append(cpes, c)
|
||||
}
|
||||
|
||||
p := pkg.Package{
|
||||
Name: classifier.Package,
|
||||
Version: version,
|
||||
Locations: source.NewLocationSet(location),
|
||||
Type: pkg.BinaryPkg,
|
||||
CPEs: cpes,
|
||||
FoundBy: catalogerName,
|
||||
MetadataType: pkg.BinaryMetadataType,
|
||||
Metadata: pkg.BinaryMetadata{
|
||||
Matches: []pkg.ClassifierMatch{
|
||||
{
|
||||
Classifier: classifier.Class,
|
||||
Location: location,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if classifier.Type != "" {
|
||||
p.Type = classifier.Type
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(classifier.PURL, emptyPURL) {
|
||||
purl := classifier.PURL
|
||||
purl.Version = version
|
||||
p.PURL = purl.ToString()
|
||||
}
|
||||
|
||||
if classifier.Language != "" {
|
||||
p.Language = classifier.Language
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
|
||||
return []pkg.Package{p}
|
||||
}
|
||||
|
||||
func getContents(resolver source.FileResolver, location source.Location) ([]byte, error) {
|
||||
reader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
|
||||
@@ -270,6 +270,17 @@ var defaultClassifiers = []classifier{
|
||||
PURL: mustPURL("pkg:generic/ruby@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:ruby-lang:ruby:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "consul-binary",
|
||||
FileGlob: "**/consul",
|
||||
EvidenceMatcher: fileContentsVersionMatcher(
|
||||
// NOTE: This is brittle and may not work for past or future versions
|
||||
`CONSUL_VERSION: (?P<version>\d+\.\d+\.\d+)`,
|
||||
),
|
||||
Package: "consul",
|
||||
PURL: mustPURL("pkg:golang/github.com/hashicorp/consul@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:hashicorp:consul:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
}
|
||||
|
||||
// in both binaries and shared libraries, the version pattern is [NUL]3.11.2[NUL]
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func newPackage(classifier classifier, location source.Location, matchMetadata map[string]string) *pkg.Package {
|
||||
version, ok := matchMetadata["version"]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
update := matchMetadata["update"]
|
||||
|
||||
var cpes []cpe.CPE
|
||||
for _, c := range classifier.CPEs {
|
||||
c.Version = version
|
||||
c.Update = update
|
||||
cpes = append(cpes, c)
|
||||
}
|
||||
|
||||
p := pkg.Package{
|
||||
Name: classifier.Package,
|
||||
Version: version,
|
||||
Locations: source.NewLocationSet(
|
||||
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
Type: pkg.BinaryPkg,
|
||||
CPEs: cpes,
|
||||
FoundBy: catalogerName,
|
||||
MetadataType: pkg.BinaryMetadataType,
|
||||
Metadata: pkg.BinaryMetadata{
|
||||
Matches: []pkg.ClassifierMatch{
|
||||
{
|
||||
Classifier: classifier.Class,
|
||||
Location: location,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if classifier.Type != "" {
|
||||
p.Type = classifier.Type
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(classifier.PURL, emptyPURL) {
|
||||
purl := classifier.PURL
|
||||
purl.Version = version
|
||||
p.PURL = purl.ToString()
|
||||
}
|
||||
|
||||
if classifier.Language != "" {
|
||||
p.Language = classifier.Language
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
|
||||
return &p
|
||||
}
|
||||
@@ -15,7 +15,9 @@ all: \
|
||||
classifiers/dynamic/kubectl-1.25.7 \
|
||||
classifiers/dynamic/kubectl-1.26.2 \
|
||||
classifiers/dynamic/kustomize-4.5.7 \
|
||||
classifiers/dynamic/kustomize-5.0.0
|
||||
classifiers/dynamic/kustomize-5.0.0 \
|
||||
classifiers/dynamic/consul-1.15.2
|
||||
|
||||
|
||||
|
||||
classifiers/dynamic/python-binary-shared-lib-3.11:
|
||||
@@ -141,6 +143,12 @@ classifiers/dynamic/kustomize-5.0.0:
|
||||
/usr/local/bin/kustomize \
|
||||
$@/kustomize
|
||||
|
||||
classifiers/dynamic/consul-1.15.2:
|
||||
$(eval $@_image := "hashicorp/consul:1.15.2@sha256:c2169f3bb18dd947ae8eb5f6766896695c71fb439f050a3343e0007d895615b8")
|
||||
./get-image-file.sh $($@_image) \
|
||||
/bin/consul \
|
||||
$@/consul
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf classifiers/dynamic
|
||||
|
||||
@@ -23,6 +23,8 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/haskell"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/nix"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/php"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/portage"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/python"
|
||||
@@ -51,8 +53,10 @@ func ImageCatalogers(cfg Config) []pkg.Cataloger {
|
||||
golang.NewGoModuleBinaryCataloger(cfg.Go()),
|
||||
dotnet.NewDotnetDepsCataloger(),
|
||||
portage.NewPortageCataloger(),
|
||||
nix.NewStoreCataloger(),
|
||||
sbom.NewSBOMCataloger(),
|
||||
binary.NewCataloger(),
|
||||
kernel.NewLinuxKernelCataloger(cfg.Kernel()),
|
||||
}, cfg.Catalogers)
|
||||
}
|
||||
|
||||
@@ -71,6 +75,7 @@ func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
|
||||
java.NewJavaCataloger(cfg.Java()),
|
||||
java.NewJavaPomCataloger(),
|
||||
java.NewNativeImageCataloger(),
|
||||
java.NewJavaGradleLockfileCataloger(),
|
||||
apkdb.NewApkdbCataloger(),
|
||||
golang.NewGoModuleBinaryCataloger(cfg.Go()),
|
||||
golang.NewGoModFileCataloger(cfg.Go()),
|
||||
@@ -85,6 +90,8 @@ func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
|
||||
binary.NewCataloger(),
|
||||
elixir.NewMixLockCataloger(),
|
||||
erlang.NewRebarLockCataloger(),
|
||||
kernel.NewLinuxKernelCataloger(cfg.Kernel()),
|
||||
nix.NewStoreCataloger(),
|
||||
}, cfg.Catalogers)
|
||||
}
|
||||
|
||||
@@ -104,6 +111,7 @@ func AllCatalogers(cfg Config) []pkg.Cataloger {
|
||||
java.NewJavaCataloger(cfg.Java()),
|
||||
java.NewJavaPomCataloger(),
|
||||
java.NewNativeImageCataloger(),
|
||||
java.NewJavaGradleLockfileCataloger(),
|
||||
apkdb.NewApkdbCataloger(),
|
||||
golang.NewGoModuleBinaryCataloger(cfg.Go()),
|
||||
golang.NewGoModFileCataloger(cfg.Go()),
|
||||
@@ -121,6 +129,8 @@ func AllCatalogers(cfg Config) []pkg.Cataloger {
|
||||
binary.NewCataloger(),
|
||||
elixir.NewMixLockCataloger(),
|
||||
erlang.NewRebarLockCataloger(),
|
||||
kernel.NewLinuxKernelCataloger(cfg.Kernel()),
|
||||
nix.NewStoreCataloger(),
|
||||
}, cfg.Catalogers)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,15 @@ package cataloger
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/golang"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
|
||||
)
|
||||
|
||||
// TODO: these field naming vs helper function naming schemes are inconsistent.
|
||||
|
||||
type Config struct {
|
||||
Search SearchConfig
|
||||
Golang golang.GoCatalogerOpts
|
||||
LinuxKernel kernel.LinuxCatalogerConfig
|
||||
Catalogers []string
|
||||
Parallelism int
|
||||
}
|
||||
@@ -16,6 +20,7 @@ func DefaultConfig() Config {
|
||||
return Config{
|
||||
Search: DefaultSearchConfig(),
|
||||
Parallelism: 1,
|
||||
LinuxKernel: kernel.DefaultLinuxCatalogerConfig(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,3 +34,7 @@ func (c Config) Java() java.Config {
|
||||
func (c Config) Go() golang.GoCatalogerOpts {
|
||||
return c.Golang
|
||||
}
|
||||
|
||||
func (c Config) Kernel() kernel.LinuxCatalogerConfig {
|
||||
return c.LinuxKernel
|
||||
}
|
||||
|
||||
@@ -48,7 +48,10 @@ func parseConanfile(_ source.FileResolver, _ *generic.Environment, reader source
|
||||
continue
|
||||
}
|
||||
|
||||
p := newConanfilePackage(m, reader.Location)
|
||||
p := newConanfilePackage(
|
||||
m,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -44,7 +44,10 @@ func parseConanlock(_ source.FileResolver, _ *generic.Environment, reader source
|
||||
Context: node.Context,
|
||||
}
|
||||
|
||||
p := newConanlockPackage(metadata, reader.Location)
|
||||
p := newConanlockPackage(
|
||||
metadata,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
if p != nil {
|
||||
pkgs = append(pkgs, *p)
|
||||
|
||||
@@ -58,7 +58,13 @@ func parsePubspecLock(_ source.FileResolver, _ *generic.Environment, reader sour
|
||||
|
||||
for _, name := range names {
|
||||
pubPkg := p.Packages[name]
|
||||
pkgs = append(pkgs, newPubspecLockPackage(name, pubPkg, reader.Location))
|
||||
pkgs = append(pkgs,
|
||||
newPubspecLockPackage(
|
||||
name,
|
||||
pubPkg,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Package dpkg provides a concrete Cataloger implementation for Debian package DB status files.
|
||||
Package deb provides a concrete Cataloger implementation for Debian package DB status files.
|
||||
*/
|
||||
package deb
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ func newDpkgPackage(d pkg.DpkgMetadata, dbLocation source.Location, resolver sou
|
||||
p := pkg.Package{
|
||||
Name: d.Package,
|
||||
Version: d.Version,
|
||||
Locations: source.NewLocationSet(dbLocation),
|
||||
Locations: source.NewLocationSet(dbLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(d, release),
|
||||
Type: pkg.DebPkg,
|
||||
MetadataType: pkg.DpkgMetadataType,
|
||||
@@ -162,6 +162,7 @@ func getAdditionalFileListing(resolver source.FileResolver, dbLocation source.Lo
|
||||
return files, locations
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func fetchMd5Contents(resolver source.FileResolver, dbLocation source.Location, m pkg.DpkgMetadata) (io.ReadCloser, *source.Location) {
|
||||
var md5Reader io.ReadCloser
|
||||
var err error
|
||||
@@ -182,17 +183,22 @@ func fetchMd5Contents(resolver source.FileResolver, dbLocation source.Location,
|
||||
location = resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "info", m.Package+md5sumsExt))
|
||||
}
|
||||
|
||||
// this is unexpected, but not a show-stopper
|
||||
if location != nil {
|
||||
md5Reader, err = resolver.FileContentsByLocation(*location)
|
||||
if err != nil {
|
||||
log.Warnf("failed to fetch deb md5 contents (package=%s): %+v", m.Package, err)
|
||||
}
|
||||
if location == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return md5Reader, location
|
||||
// this is unexpected, but not a show-stopper
|
||||
md5Reader, err = resolver.FileContentsByLocation(*location)
|
||||
if err != nil {
|
||||
log.Warnf("failed to fetch deb md5 contents (package=%s): %+v", m.Package, err)
|
||||
}
|
||||
|
||||
l := location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)
|
||||
|
||||
return md5Reader, &l
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func fetchConffileContents(resolver source.FileResolver, dbLocation source.Location, m pkg.DpkgMetadata) (io.ReadCloser, *source.Location) {
|
||||
var reader io.ReadCloser
|
||||
var err error
|
||||
@@ -213,15 +219,19 @@ func fetchConffileContents(resolver source.FileResolver, dbLocation source.Locat
|
||||
location = resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "info", m.Package+conffilesExt))
|
||||
}
|
||||
|
||||
// this is unexpected, but not a show-stopper
|
||||
if location != nil {
|
||||
reader, err = resolver.FileContentsByLocation(*location)
|
||||
if err != nil {
|
||||
log.Warnf("failed to fetch deb conffiles contents (package=%s): %+v", m.Package, err)
|
||||
}
|
||||
if location == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return reader, location
|
||||
// this is unexpected, but not a show-stopper
|
||||
reader, err = resolver.FileContentsByLocation(*location)
|
||||
if err != nil {
|
||||
log.Warnf("failed to fetch deb conffiles contents (package=%s): %+v", m.Package, err)
|
||||
}
|
||||
|
||||
l := location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)
|
||||
|
||||
return reader, &l
|
||||
}
|
||||
|
||||
func fetchCopyrightContents(resolver source.FileResolver, dbLocation source.Location, m pkg.DpkgMetadata) (io.ReadCloser, *source.Location) {
|
||||
@@ -243,7 +253,9 @@ func fetchCopyrightContents(resolver source.FileResolver, dbLocation source.Loca
|
||||
log.Warnf("failed to fetch deb copyright contents (package=%s): %w", m.Package, err)
|
||||
}
|
||||
|
||||
return reader, location
|
||||
l := location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)
|
||||
|
||||
return reader, &l
|
||||
}
|
||||
|
||||
func md5Key(metadata pkg.DpkgMetadata) string {
|
||||
|
||||
@@ -45,7 +45,11 @@ func parseDotnetDeps(_ source.FileResolver, _ *generic.Environment, reader sourc
|
||||
|
||||
for _, nameVersion := range names {
|
||||
lib := p.Libraries[nameVersion]
|
||||
dotnetPkg := newDotnetDepsPackage(nameVersion, lib, reader.Location)
|
||||
dotnetPkg := newDotnetDepsPackage(
|
||||
nameVersion,
|
||||
lib,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
if dotnetPkg != nil {
|
||||
pkgs = append(pkgs, *dotnetPkg)
|
||||
|
||||
@@ -43,11 +43,16 @@ func parseMixLock(_ source.FileResolver, _ *generic.Environment, reader source.L
|
||||
continue
|
||||
}
|
||||
|
||||
packages = append(packages, newPackage(pkg.MixLockMetadata{
|
||||
Name: name,
|
||||
Version: version,
|
||||
PkgHash: hash,
|
||||
PkgHashExt: hashExt,
|
||||
}))
|
||||
packages = append(packages,
|
||||
newPackage(
|
||||
pkg.MixLockMetadata{
|
||||
Name: name,
|
||||
Version: version,
|
||||
PkgHash: hash,
|
||||
PkgHashExt: hashExt,
|
||||
},
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,18 @@ import (
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func TestParseMixLock(t *testing.T) {
|
||||
locations := source.NewLocationSet(source.NewLocation("test-fixtures/mix.lock"))
|
||||
expected := []pkg.Package{
|
||||
{
|
||||
Name: "castore",
|
||||
Version: "0.1.17",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/castore@0.1.17",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -29,6 +32,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "1.1.0",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/connection@1.1.0",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -43,6 +47,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "2.9.0",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/cowboy@2.9.0",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -57,6 +62,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "0.4.0",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/cowboy_telemetry@0.4.0",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -71,6 +77,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "2.11.0",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/cowlib@2.11.0",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -85,6 +92,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "2.4.2",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/db_connection@2.4.2",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -99,6 +107,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "2.0.0",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/decimal@2.0.0",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -113,6 +122,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "1.4.25",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/earmark_parser@1.4.25",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -127,6 +137,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "3.8.1",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/ecto@3.8.1",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -141,6 +152,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "3.8.1",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/ecto_sql@3.8.1",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -155,6 +167,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "0.5.0",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/esbuild@0.5.0",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -169,6 +182,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "0.28.4",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/ex_doc@0.28.4",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -183,6 +197,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "0.19.1",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/gettext@0.19.1",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -197,6 +212,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "0.1.1",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/hpax@0.1.1",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
@@ -211,6 +227,7 @@ func TestParseMixLock(t *testing.T) {
|
||||
Version: "1.3.0",
|
||||
Language: pkg.Elixir,
|
||||
Type: pkg.HexPkg,
|
||||
Locations: locations,
|
||||
PURL: "pkg:hex/jason@1.3.0",
|
||||
MetadataType: pkg.MixLockMetadataType,
|
||||
Metadata: pkg.MixLockMetadata{
|
||||
|
||||
@@ -48,10 +48,13 @@ func parseRebarLock(_ source.FileResolver, _ *generic.Environment, reader source
|
||||
version = versionNode.Get(2).Get(1).String()
|
||||
}
|
||||
|
||||
p := newPackage(pkg.RebarLockMetadata{
|
||||
Name: name,
|
||||
Version: version,
|
||||
})
|
||||
p := newPackage(
|
||||
pkg.RebarLockMetadata{
|
||||
Name: name,
|
||||
Version: version,
|
||||
},
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
pkgMap[name] = &p
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func TestParseRebarLock(t *testing.T) {
|
||||
@@ -261,6 +262,10 @@ func TestParseRebarLock(t *testing.T) {
|
||||
// TODO: relationships are not under test
|
||||
var expectedRelationships []artifact.Relationship
|
||||
|
||||
for idx := range test.expected {
|
||||
test.expected[idx].Locations = source.NewLocationSet(source.NewLocation(test.fixture))
|
||||
}
|
||||
|
||||
pkgtest.TestFileParser(t, test.fixture, parseRebarLock, test.expected, expectedRelationships)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/go-git/go-billy/v5"
|
||||
)
|
||||
|
||||
// billyFSAdapter is a fs.FS, fs.ReadDirFS, and fs.StatFS wrapping what billyfs returns
|
||||
type billyFSAdapter struct {
|
||||
fs billy.Filesystem
|
||||
}
|
||||
|
||||
func (b billyFSAdapter) Stat(name string) (fs.FileInfo, error) {
|
||||
return b.fs.Stat(name)
|
||||
}
|
||||
|
||||
func (b billyFSAdapter) ReadDir(name string) (out []fs.DirEntry, _ error) {
|
||||
entries, err := b.fs.ReadDir(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, e := range entries {
|
||||
out = append(out, billyDirEntry{fi: e})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b billyFSAdapter) Open(name string) (fs.File, error) {
|
||||
f, err := b.fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fi, err := b.Stat(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return billyFile{f: f, fi: fi}, nil
|
||||
}
|
||||
|
||||
var _ fs.FS = (*billyFSAdapter)(nil)
|
||||
var _ fs.ReadDirFS = (*billyFSAdapter)(nil)
|
||||
var _ fs.StatFS = (*billyFSAdapter)(nil)
|
||||
|
||||
// billyFile is a fs.File wrapping what billyfs returns
|
||||
type billyFile struct {
|
||||
f billy.File
|
||||
fi fs.FileInfo
|
||||
}
|
||||
|
||||
func (b billyFile) Stat() (fs.FileInfo, error) {
|
||||
return b.fi, nil
|
||||
}
|
||||
|
||||
func (b billyFile) Read(i []byte) (int, error) {
|
||||
return b.f.Read(i)
|
||||
}
|
||||
|
||||
func (b billyFile) Close() error {
|
||||
return b.f.Close()
|
||||
}
|
||||
|
||||
var _ fs.File = (*billyFile)(nil)
|
||||
|
||||
// billyDirEntry is a fs.DirEntry wrapping what billyfs returns
|
||||
type billyDirEntry struct {
|
||||
fi os.FileInfo
|
||||
}
|
||||
|
||||
func (b billyDirEntry) Name() string {
|
||||
return b.fi.Name()
|
||||
}
|
||||
|
||||
func (b billyDirEntry) IsDir() bool {
|
||||
return b.fi.IsDir()
|
||||
}
|
||||
|
||||
func (b billyDirEntry) Type() fs.FileMode {
|
||||
return b.fi.Mode()
|
||||
}
|
||||
|
||||
func (b billyDirEntry) Info() (fs.FileInfo, error) {
|
||||
return b.fi, nil
|
||||
}
|
||||
|
||||
var _ fs.DirEntry = (*billyDirEntry)(nil)
|
||||
@@ -0,0 +1,33 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_billyFSAdapter(t *testing.T) {
|
||||
r, err := git.PlainInit("test-fixtures/repo", false)
|
||||
|
||||
t.Cleanup(func() {
|
||||
_ = os.RemoveAll("test-fixtures/repo/.git")
|
||||
})
|
||||
|
||||
wt, err := r.Worktree()
|
||||
require.NoError(t, err)
|
||||
f := billyFSAdapter{
|
||||
fs: wt.Filesystem,
|
||||
}
|
||||
|
||||
found := ""
|
||||
err = fs.WalkDir(f, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
found = path
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "LICENSE", found)
|
||||
}
|
||||
@@ -5,28 +5,47 @@ package golang
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
type GoCatalogerOpts struct {
|
||||
SearchLocalModCacheLicenses bool
|
||||
LocalModCacheDir string
|
||||
}
|
||||
|
||||
// NewGoModFileCataloger returns a new Go module cataloger object.
|
||||
func NewGoModFileCataloger(opts GoCatalogerOpts) *generic.Cataloger {
|
||||
func NewGoModFileCataloger(opts GoCatalogerOpts) pkg.Cataloger {
|
||||
c := goModCataloger{
|
||||
licenses: newGoLicenses(opts),
|
||||
}
|
||||
return generic.NewCataloger("go-mod-file-cataloger").
|
||||
WithParserByGlobs(c.parseGoModFile, "**/go.mod")
|
||||
return &progressingCataloger{
|
||||
progress: c.licenses.progress,
|
||||
cataloger: generic.NewCataloger("go-mod-file-cataloger").
|
||||
WithParserByGlobs(c.parseGoModFile, "**/go.mod"),
|
||||
}
|
||||
}
|
||||
|
||||
// NewGoModuleBinaryCataloger returns a new Golang cataloger object.
|
||||
func NewGoModuleBinaryCataloger(opts GoCatalogerOpts) *generic.Cataloger {
|
||||
func NewGoModuleBinaryCataloger(opts GoCatalogerOpts) pkg.Cataloger {
|
||||
c := goBinaryCataloger{
|
||||
licenses: newGoLicenses(opts),
|
||||
}
|
||||
return generic.NewCataloger("go-module-binary-cataloger").
|
||||
WithParserByMimeTypes(c.parseGoBinary, internal.ExecutableMIMETypeSet.List()...)
|
||||
return &progressingCataloger{
|
||||
progress: c.licenses.progress,
|
||||
cataloger: generic.NewCataloger("go-module-binary-cataloger").
|
||||
WithParserByMimeTypes(c.parseGoBinary, internal.ExecutableMIMETypeSet.List()...),
|
||||
}
|
||||
}
|
||||
|
||||
type progressingCataloger struct {
|
||||
progress *event.CatalogerTask
|
||||
cataloger *generic.Cataloger
|
||||
}
|
||||
|
||||
func (p *progressingCataloger) Name() string {
|
||||
return p.cataloger.Name()
|
||||
}
|
||||
|
||||
func (p *progressingCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
defer p.progress.SetCompleted()
|
||||
return p.cataloger.Catalog(resolver)
|
||||
}
|
||||
|
||||
@@ -1,105 +1,158 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/go-git/go-billy/v5/memfs"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/storage/memory"
|
||||
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
type goLicenses struct {
|
||||
searchLocalModCacheLicenses bool
|
||||
localModCacheResolver source.FileResolver
|
||||
opts GoCatalogerOpts
|
||||
localModCacheResolver source.WritableFileResolver
|
||||
progress *event.CatalogerTask
|
||||
}
|
||||
|
||||
func newGoLicenses(opts GoCatalogerOpts) goLicenses {
|
||||
return goLicenses{
|
||||
searchLocalModCacheLicenses: opts.SearchLocalModCacheLicenses,
|
||||
localModCacheResolver: modCacheResolver(opts.LocalModCacheDir),
|
||||
opts: opts,
|
||||
localModCacheResolver: modCacheResolver(opts.localModCacheDir),
|
||||
progress: &event.CatalogerTask{
|
||||
SubStatus: true,
|
||||
RemoveOnCompletion: true,
|
||||
Title: "Downloading go mod",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func defaultGoPath() string {
|
||||
goPath := os.Getenv("GOPATH")
|
||||
|
||||
if goPath == "" {
|
||||
homeDir, err := homedir.Dir()
|
||||
if err != nil {
|
||||
log.Debug("unable to determine user home dir: %v", err)
|
||||
} else {
|
||||
goPath = path.Join(homeDir, "go")
|
||||
func remotesForModule(proxies []string, noProxy []string, module string) []string {
|
||||
for _, pattern := range noProxy {
|
||||
if matched, err := path.Match(pattern, module); err == nil && matched {
|
||||
// matched to be direct for this module
|
||||
return directProxiesOnly
|
||||
}
|
||||
}
|
||||
|
||||
return goPath
|
||||
return proxies
|
||||
}
|
||||
|
||||
// resolver needs to be shared between mod file & binary scanners so it's only scanned once
|
||||
var modCacheResolvers = map[string]source.FileResolver{}
|
||||
|
||||
func modCacheResolver(modCacheDir string) source.FileResolver {
|
||||
if modCacheDir == "" {
|
||||
goPath := defaultGoPath()
|
||||
if goPath != "" {
|
||||
modCacheDir = path.Join(goPath, "pkg", "mod")
|
||||
}
|
||||
}
|
||||
|
||||
if r, ok := modCacheResolvers[modCacheDir]; ok {
|
||||
return r
|
||||
}
|
||||
|
||||
var r source.FileResolver
|
||||
func modCacheResolver(modCacheDir string) source.WritableFileResolver {
|
||||
var r source.WritableFileResolver
|
||||
|
||||
if modCacheDir == "" {
|
||||
log.Trace("unable to determine mod cache directory, skipping mod cache resolver")
|
||||
r = source.NewMockResolverForPaths()
|
||||
r = source.EmptyResolver{}
|
||||
} else {
|
||||
stat, err := os.Stat(modCacheDir)
|
||||
|
||||
if os.IsNotExist(err) || stat == nil || !stat.IsDir() {
|
||||
log.Tracef("unable to open mod cache directory: %s, skipping mod cache resolver", modCacheDir)
|
||||
r = source.NewMockResolverForPaths()
|
||||
r = source.EmptyResolver{}
|
||||
} else {
|
||||
r = source.NewDeferredResolverFromSource(func() (source.Source, error) {
|
||||
return source.NewFromDirectory(modCacheDir)
|
||||
})
|
||||
r = source.NewUnindexedDirectoryResolver(modCacheDir)
|
||||
}
|
||||
}
|
||||
|
||||
modCacheResolvers[modCacheDir] = r
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (c *goLicenses) getLicenses(resolver source.FileResolver, moduleName, moduleVersion string) (licenses []string, err error) {
|
||||
moduleName = processCaps(moduleName)
|
||||
|
||||
licenses, err = findLicenses(resolver,
|
||||
fmt.Sprintf(`**/go/pkg/mod/%s@%s/*`, moduleName, moduleVersion),
|
||||
fmt.Sprintf(`**/go/pkg/mod/%s@%s/*`, processCaps(moduleName), moduleVersion),
|
||||
)
|
||||
|
||||
if c.searchLocalModCacheLicenses && err == nil && len(licenses) == 0 {
|
||||
// if we're running against a directory on the filesystem, it may not include the
|
||||
// user's homedir / GOPATH, so we defer to using the localModCacheResolver
|
||||
licenses, err = findLicenses(c.localModCacheResolver,
|
||||
fmt.Sprintf(`**/%s@%s/*`, moduleName, moduleVersion),
|
||||
)
|
||||
if err != nil || len(licenses) > 0 {
|
||||
return requireCollection(licenses), err
|
||||
}
|
||||
|
||||
// always return a non-nil slice
|
||||
// look in the local host mod cache...
|
||||
licenses, err = c.getLicensesFromLocal(moduleName, moduleVersion)
|
||||
if err != nil || len(licenses) > 0 {
|
||||
return requireCollection(licenses), err
|
||||
}
|
||||
|
||||
// we did not find it yet and remote searching was enabled
|
||||
licenses, err = c.getLicensesFromRemote(moduleName, moduleVersion)
|
||||
return requireCollection(licenses), err
|
||||
}
|
||||
|
||||
func (c *goLicenses) getLicensesFromLocal(moduleName, moduleVersion string) ([]string, error) {
|
||||
if !c.opts.searchLocalModCacheLicenses {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// if we're running against a directory on the filesystem, it may not include the
|
||||
// user's homedir / GOPATH, so we defer to using the localModCacheResolver
|
||||
return findLicenses(c.localModCacheResolver, moduleSearchGlob(moduleName, moduleVersion))
|
||||
}
|
||||
|
||||
func (c *goLicenses) getLicensesFromRemote(moduleName, moduleVersion string) ([]string, error) {
|
||||
if !c.opts.searchRemoteLicenses {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
proxies := remotesForModule(c.opts.proxies, c.opts.noProxy, moduleName)
|
||||
|
||||
fsys, err := getModule(c.progress, proxies, moduleName, moduleVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dir := moduleDir(moduleName, moduleVersion)
|
||||
|
||||
// populate the mod cache with the results
|
||||
err = fs.WalkDir(fsys, ".", func(filePath string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
return nil
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
f, err := fsys.Open(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.localModCacheResolver.Write(source.NewLocation(path.Join(dir, filePath)), f)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Tracef("remote proxy walk failed for: %s", moduleName)
|
||||
}
|
||||
|
||||
return findLicenses(c.localModCacheResolver, moduleSearchGlob(moduleName, moduleVersion))
|
||||
}
|
||||
|
||||
func moduleDir(moduleName, moduleVersion string) string {
|
||||
return fmt.Sprintf("%s@%s", processCaps(moduleName), moduleVersion)
|
||||
}
|
||||
|
||||
func moduleSearchGlob(moduleName, moduleVersion string) string {
|
||||
return fmt.Sprintf("%s/*", moduleDir(moduleName, moduleVersion))
|
||||
}
|
||||
|
||||
func requireCollection(licenses []string) []string {
|
||||
if licenses == nil {
|
||||
licenses = []string{}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
return
|
||||
return licenses
|
||||
}
|
||||
|
||||
func findLicenses(resolver source.FileResolver, globMatch string) (out []string, err error) {
|
||||
@@ -138,3 +191,96 @@ func processCaps(s string) string {
|
||||
return "!" + strings.ToLower(s)
|
||||
})
|
||||
}
|
||||
|
||||
func getModule(progress *event.CatalogerTask, proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
|
||||
for _, proxy := range proxies {
|
||||
u, _ := url.Parse(proxy)
|
||||
if proxy == "direct" {
|
||||
fsys, err = getModuleRepository(progress, moduleName, moduleVersion)
|
||||
continue
|
||||
}
|
||||
switch u.Scheme {
|
||||
case "https", "http":
|
||||
fsys, err = getModuleProxy(progress, proxy, moduleName, moduleVersion)
|
||||
case "file":
|
||||
p := filepath.Join(u.Path, moduleName, "@v", moduleVersion)
|
||||
progress.SetValue(fmt.Sprintf("file: %s", p))
|
||||
fsys = os.DirFS(p)
|
||||
}
|
||||
if fsys != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getModuleProxy(progress *event.CatalogerTask, proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
|
||||
u := fmt.Sprintf("%s/%s/@v/%s.zip", proxy, moduleName, moduleVersion)
|
||||
progress.SetValue(u)
|
||||
// get the module zip
|
||||
resp, err := http.Get(u) //nolint:gosec
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
u = fmt.Sprintf("%s/%s/@v/%s.zip", proxy, strings.ToLower(moduleName), moduleVersion)
|
||||
progress.SetValue(u)
|
||||
// try lowercasing it; some packages have mixed casing that really messes up the proxy
|
||||
resp, err = http.Get(u) //nolint:gosec
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to get module zip: %s", resp.Status)
|
||||
}
|
||||
}
|
||||
// read the zip
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err = zip.NewReader(bytes.NewReader(b), resp.ContentLength)
|
||||
versionPath := findVersionPath(out, ".")
|
||||
out = getSubFS(out, versionPath)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func findVersionPath(f fs.FS, dir string) string {
|
||||
list, _ := fs.ReadDir(f, dir)
|
||||
for _, entry := range list {
|
||||
name := entry.Name()
|
||||
if strings.Contains(name, "@") {
|
||||
return name
|
||||
}
|
||||
found := findVersionPath(f, path.Join(dir, name))
|
||||
if found != "" {
|
||||
return path.Join(name, found)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getModuleRepository(progress *event.CatalogerTask, moduleName string, moduleVersion string) (fs.FS, error) {
|
||||
repoName := moduleName
|
||||
parts := strings.Split(moduleName, "/")
|
||||
if len(parts) > 2 {
|
||||
repoName = fmt.Sprintf("%s/%s/%s", parts[0], parts[1], parts[2])
|
||||
}
|
||||
progress.SetValue(fmt.Sprintf("git: %s", repoName))
|
||||
f := memfs.New()
|
||||
buf := &bytes.Buffer{}
|
||||
_, err := git.Clone(memory.NewStorage(), f, &git.CloneOptions{
|
||||
URL: fmt.Sprintf("https://%s", repoName),
|
||||
ReferenceName: plumbing.NewTagReferenceName(moduleVersion), // FIXME version might be a SHA
|
||||
SingleBranch: true,
|
||||
Depth: 1,
|
||||
Progress: buf,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w -- %s", err, buf.String())
|
||||
}
|
||||
|
||||
return billyFSAdapter{fs: f}, nil
|
||||
}
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -10,7 +16,7 @@ import (
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func Test_LicenseSearch(t *testing.T) {
|
||||
func Test_LocalLicenseSearch(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
version string
|
||||
@@ -34,10 +40,85 @@ func Test_LicenseSearch(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
l := newGoLicenses(GoCatalogerOpts{
|
||||
SearchLocalModCacheLicenses: true,
|
||||
LocalModCacheDir: path.Join(wd, "test-fixtures", "licenses"),
|
||||
searchLocalModCacheLicenses: true,
|
||||
localModCacheDir: path.Join(wd, "test-fixtures", "licenses", "pkg", "mod"),
|
||||
})
|
||||
licenses, err := l.getLicenses(source.MockResolver{}, test.name, test.version)
|
||||
licenses, err := l.getLicenses(source.EmptyResolver{}, test.name, test.version)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, licenses, 1)
|
||||
|
||||
require.Equal(t, test.expected, licenses[0])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_RemoteProxyLicenseSearch(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
buf := &bytes.Buffer{}
|
||||
uri := strings.TrimPrefix(strings.TrimSuffix(r.RequestURI, ".zip"), "/")
|
||||
|
||||
parts := strings.Split(uri, "/@v/")
|
||||
modPath := parts[0]
|
||||
modVersion := parts[1]
|
||||
|
||||
wd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
testDir := path.Join(wd, "test-fixtures", "licenses", "pkg", "mod", processCaps(modPath)+"@"+modVersion)
|
||||
|
||||
archive := zip.NewWriter(buf)
|
||||
|
||||
entries, err := os.ReadDir(testDir)
|
||||
require.NoError(t, err)
|
||||
for _, f := range entries {
|
||||
// the zip files downloaded contain a path to the repo that somewhat matches where it ends up on disk,
|
||||
// so prefix entries with something similar
|
||||
writer, err := archive.Create(path.Join("github.com/something/some@version", f.Name()))
|
||||
require.NoError(t, err)
|
||||
contents, err := os.ReadFile(path.Join(testDir, f.Name()))
|
||||
require.NoError(t, err)
|
||||
_, err = writer.Write(contents)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
err = archive.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
w.Header().Add("Content-Length", fmt.Sprintf("%d", buf.Len()))
|
||||
|
||||
_, err = w.Write(buf.Bytes())
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
version string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "github.com/someorg/somename",
|
||||
version: "v0.3.2",
|
||||
expected: "Apache-2.0",
|
||||
},
|
||||
{
|
||||
name: "github.com/CapORG/CapProject",
|
||||
version: "v4.111.5",
|
||||
expected: "MIT",
|
||||
},
|
||||
}
|
||||
|
||||
modDir := path.Join(t.TempDir())
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
l := newGoLicenses(GoCatalogerOpts{
|
||||
searchRemoteLicenses: true,
|
||||
proxies: []string{server.URL},
|
||||
localModCacheDir: modDir,
|
||||
})
|
||||
|
||||
licenses, err := l.getLicenses(source.EmptyResolver{}, test.name, test.version)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, licenses, 1)
|
||||
@@ -74,3 +155,42 @@ func Test_processCaps(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_remotesForModule(t *testing.T) {
|
||||
allProxies := []string{"https://somewhere.org", "direct"}
|
||||
directProxy := []string{"direct"}
|
||||
|
||||
tests := []struct {
|
||||
module string
|
||||
noProxy string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
module: "github.com/anchore/syft",
|
||||
expected: allProxies,
|
||||
},
|
||||
{
|
||||
module: "github.com/anchore/sbom-action",
|
||||
noProxy: "*/anchore/*",
|
||||
expected: directProxy,
|
||||
},
|
||||
{
|
||||
module: "github.com/anchore/sbom-action",
|
||||
noProxy: "*/user/mod,*/anchore/sbom-action",
|
||||
expected: directProxy,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.module, func(t *testing.T) {
|
||||
got := remotesForModule(allProxies, strings.Split(test.noProxy, ","), test.module)
|
||||
require.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_findVersionPath(t *testing.T) {
|
||||
f := os.DirFS("test-fixtures/zip-fs")
|
||||
vp := findVersionPath(f, ".")
|
||||
require.Equal(t, "github.com/someorg/somepkg@version", vp)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultProxies = "https://proxy.golang.org,direct"
|
||||
directProxyOnly = "direct"
|
||||
)
|
||||
|
||||
var (
|
||||
directProxiesOnly = []string{directProxyOnly}
|
||||
)
|
||||
|
||||
type GoCatalogerOpts struct {
|
||||
searchLocalModCacheLicenses bool
|
||||
localModCacheDir string
|
||||
searchRemoteLicenses bool
|
||||
proxies []string
|
||||
noProxy []string
|
||||
}
|
||||
|
||||
func (g GoCatalogerOpts) WithSearchLocalModCacheLicenses(input bool) GoCatalogerOpts {
|
||||
g.searchLocalModCacheLicenses = input
|
||||
return g
|
||||
}
|
||||
|
||||
func (g GoCatalogerOpts) WithLocalModCacheDir(input string) GoCatalogerOpts {
|
||||
if input == "" {
|
||||
return g
|
||||
}
|
||||
g.localModCacheDir = input
|
||||
return g
|
||||
}
|
||||
|
||||
func (g GoCatalogerOpts) WithSearchRemoteLicenses(input bool) GoCatalogerOpts {
|
||||
g.searchRemoteLicenses = input
|
||||
return g
|
||||
}
|
||||
|
||||
func (g GoCatalogerOpts) WithProxy(input string) GoCatalogerOpts {
|
||||
if input == "" {
|
||||
return g
|
||||
}
|
||||
if input == "off" {
|
||||
input = directProxyOnly
|
||||
}
|
||||
g.proxies = strings.Split(input, ",")
|
||||
return g
|
||||
}
|
||||
|
||||
func (g GoCatalogerOpts) WithNoProxy(input string) GoCatalogerOpts {
|
||||
if input == "" {
|
||||
return g
|
||||
}
|
||||
g.noProxy = strings.Split(input, ",")
|
||||
return g
|
||||
}
|
||||
|
||||
// NewGoCatalogerOpts create a GoCatalogerOpts with default options, which includes:
|
||||
// - setting the default remote proxy if none is provided
|
||||
// - setting the default no proxy if none is provided
|
||||
// - setting the default local module cache dir if none is provided
|
||||
func NewGoCatalogerOpts() GoCatalogerOpts {
|
||||
g := GoCatalogerOpts{}
|
||||
|
||||
// first process the proxy settings
|
||||
if len(g.proxies) == 0 {
|
||||
goProxy := os.Getenv("GOPROXY")
|
||||
if goProxy == "" {
|
||||
goProxy = defaultProxies
|
||||
}
|
||||
g = g.WithProxy(goProxy)
|
||||
}
|
||||
|
||||
// next process the gonoproxy settings
|
||||
if len(g.noProxy) == 0 {
|
||||
goPrivate := os.Getenv("GOPRIVATE")
|
||||
goNoProxy := os.Getenv("GONOPROXY")
|
||||
// we only use the env var if it was not set explicitly
|
||||
if goPrivate != "" {
|
||||
g.noProxy = append(g.noProxy, strings.Split(goPrivate, ",")...)
|
||||
}
|
||||
|
||||
// next process the goprivate settings; we always add those
|
||||
if goNoProxy != "" {
|
||||
g.noProxy = append(g.noProxy, strings.Split(goNoProxy, ",")...)
|
||||
}
|
||||
}
|
||||
|
||||
if g.localModCacheDir == "" {
|
||||
goPath := os.Getenv("GOPATH")
|
||||
|
||||
if goPath == "" {
|
||||
homeDir, err := homedir.Dir()
|
||||
if err != nil {
|
||||
log.Debug("unable to determine user home dir: %v", err)
|
||||
} else {
|
||||
goPath = path.Join(homeDir, "go")
|
||||
}
|
||||
}
|
||||
if goPath != "" {
|
||||
g.localModCacheDir = path.Join(goPath, "pkg", "mod")
|
||||
}
|
||||
}
|
||||
return g
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Options(t *testing.T) {
|
||||
type opts struct {
|
||||
local bool
|
||||
cacheDir string
|
||||
remote bool
|
||||
proxy string
|
||||
noProxy string
|
||||
}
|
||||
|
||||
homedirCacheDisabled := homedir.DisableCache
|
||||
homedir.DisableCache = true
|
||||
t.Cleanup(func() {
|
||||
homedir.DisableCache = homedirCacheDisabled
|
||||
})
|
||||
|
||||
allEnv := map[string]string{
|
||||
"HOME": "/usr/home",
|
||||
"GOPATH": "",
|
||||
"GOPROXY": "",
|
||||
"GOPRIVATE": "",
|
||||
"GONOPROXY": "",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
env map[string]string
|
||||
opts opts
|
||||
expected GoCatalogerOpts
|
||||
}{
|
||||
{
|
||||
name: "set via env defaults",
|
||||
env: map[string]string{
|
||||
"GOPATH": "/go",
|
||||
"GOPROXY": "https://my.proxy",
|
||||
"GOPRIVATE": "my.private",
|
||||
"GONOPROXY": "no.proxy",
|
||||
},
|
||||
opts: opts{},
|
||||
expected: GoCatalogerOpts{
|
||||
searchLocalModCacheLicenses: false,
|
||||
localModCacheDir: "/go/pkg/mod",
|
||||
searchRemoteLicenses: false,
|
||||
proxies: []string{"https://my.proxy"},
|
||||
noProxy: []string{"my.private", "no.proxy"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "set via configuration",
|
||||
env: map[string]string{
|
||||
"GOPATH": "/go",
|
||||
"GOPROXY": "https://my.proxy",
|
||||
"GOPRIVATE": "my.private",
|
||||
"GONOPROXY": "no.proxy",
|
||||
},
|
||||
opts: opts{
|
||||
local: true,
|
||||
cacheDir: "/go-cache",
|
||||
remote: true,
|
||||
proxy: "https://alt.proxy,direct",
|
||||
noProxy: "alt.no.proxy",
|
||||
},
|
||||
expected: GoCatalogerOpts{
|
||||
searchLocalModCacheLicenses: true,
|
||||
localModCacheDir: "/go-cache",
|
||||
searchRemoteLicenses: true,
|
||||
proxies: []string{"https://alt.proxy", "direct"},
|
||||
noProxy: []string{"alt.no.proxy"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
for k, v := range allEnv {
|
||||
t.Setenv(k, v)
|
||||
}
|
||||
for k, v := range test.env {
|
||||
t.Setenv(k, v)
|
||||
}
|
||||
got := NewGoCatalogerOpts().
|
||||
WithSearchLocalModCacheLicenses(test.opts.local).
|
||||
WithLocalModCacheDir(test.opts.cacheDir).
|
||||
WithSearchRemoteLicenses(test.opts.remote).
|
||||
WithProxy(test.opts.proxy).
|
||||
WithNoProxy(test.opts.noProxy)
|
||||
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,15 @@ func (c *goBinaryCataloger) parseGoBinary(resolver source.FileResolver, _ *gener
|
||||
|
||||
func (c *goBinaryCataloger) makeGoMainPackage(resolver source.FileResolver, mod *debug.BuildInfo, arch string, location source.Location) pkg.Package {
|
||||
gbs := getBuildSettings(mod.Settings)
|
||||
main := c.newGoBinaryPackage(resolver, &mod.Main, mod.Main.Path, mod.GoVersion, arch, gbs, location)
|
||||
main := c.newGoBinaryPackage(
|
||||
resolver,
|
||||
&mod.Main,
|
||||
mod.Main.Path,
|
||||
mod.GoVersion,
|
||||
arch,
|
||||
gbs,
|
||||
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
if main.Version == devel {
|
||||
if version, ok := gbs["vcs.revision"]; ok {
|
||||
if timestamp, ok := gbs["vcs.time"]; ok {
|
||||
@@ -204,7 +212,15 @@ func (c *goBinaryCataloger) buildGoPkgInfo(resolver source.FileResolver, locatio
|
||||
if dep == nil {
|
||||
continue
|
||||
}
|
||||
p := c.newGoBinaryPackage(resolver, dep, mod.Main.Path, mod.GoVersion, arch, nil, location)
|
||||
p := c.newGoBinaryPackage(
|
||||
resolver,
|
||||
dep,
|
||||
mod.Main.Path,
|
||||
mod.GoVersion,
|
||||
arch,
|
||||
nil,
|
||||
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
if pkg.IsValid(&p) {
|
||||
pkgs = append(pkgs, p)
|
||||
}
|
||||
|
||||
@@ -136,12 +136,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Version: "(devel)",
|
||||
PURL: "pkg:golang/github.com/anchore/syft@(devel)",
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
@@ -183,12 +183,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{},
|
||||
@@ -226,12 +226,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
@@ -262,12 +262,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
@@ -320,12 +320,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Version: "v0.0.0-20221014195457-41bc6bb41035",
|
||||
PURL: "pkg:golang/github.com/anchore/syft@v0.0.0-20221014195457-41bc6bb41035",
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
@@ -375,12 +375,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
@@ -397,12 +397,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
@@ -452,12 +452,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
@@ -473,12 +473,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
@@ -502,15 +502,15 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
}
|
||||
p.SetID()
|
||||
}
|
||||
location := source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
location := source.NewLocationFromCoordinates(
|
||||
source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
c := goBinaryCataloger{}
|
||||
pkgs := c.buildGoPkgInfo(source.NewMockResolverForPaths(), location, test.mod, test.arch)
|
||||
pkgs := c.buildGoPkgInfo(source.EmptyResolver{}, location, test.mod, test.arch)
|
||||
assert.Equal(t, test.expected, pkgs)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (c *goModCataloger) parseGoModFile(resolver source.FileResolver, _ *generic
|
||||
Name: m.Mod.Path,
|
||||
Version: m.Mod.Version,
|
||||
Licenses: licenses,
|
||||
Locations: source.NewLocationSet(reader.Location),
|
||||
Locations: source.NewLocationSet(reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(m.Mod.Path, m.Mod.Version),
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
@@ -73,7 +73,7 @@ func (c *goModCataloger) parseGoModFile(resolver source.FileResolver, _ *generic
|
||||
Name: m.New.Path,
|
||||
Version: m.New.Version,
|
||||
Licenses: licenses,
|
||||
Locations: source.NewLocationSet(reader.Location),
|
||||
Locations: source.NewLocationSet(reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(m.New.Path, m.New.Version),
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
type subFS struct {
|
||||
root string
|
||||
f fs.FS
|
||||
}
|
||||
|
||||
func getSubFS(f fs.FS, root string) fs.FS {
|
||||
if s, ok := f.(fs.SubFS); ok {
|
||||
s, err := s.Sub(root)
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return newSubFS(f, root)
|
||||
}
|
||||
|
||||
func newSubFS(f fs.FS, root string) fs.FS {
|
||||
return subFS{
|
||||
root: root,
|
||||
f: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (s subFS) Open(name string) (fs.File, error) {
|
||||
if name == "." {
|
||||
return rootFile{
|
||||
s: s,
|
||||
}, nil
|
||||
}
|
||||
return s.f.Open(path.Join(s.root, name))
|
||||
}
|
||||
|
||||
type rootFile struct {
|
||||
s subFS
|
||||
}
|
||||
|
||||
func (r rootFile) Name() string {
|
||||
return "."
|
||||
}
|
||||
|
||||
func (r rootFile) Size() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (r rootFile) Mode() fs.FileMode {
|
||||
return fs.ModePerm
|
||||
}
|
||||
|
||||
func (r rootFile) ModTime() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
func (r rootFile) IsDir() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (r rootFile) Sys() any {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r rootFile) ReadDir(_ int) ([]fs.DirEntry, error) {
|
||||
return fs.ReadDir(r.s.f, r.s.root)
|
||||
}
|
||||
|
||||
func (r rootFile) Stat() (fs.FileInfo, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r rootFile) Read(_ []byte) (int, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (r rootFile) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ fs.File = (*rootFile)(nil)
|
||||
var _ fs.ReadDirFile = (*rootFile)(nil)
|
||||
var _ fs.FileInfo = (*rootFile)(nil)
|
||||
|
||||
type subFsFileInfo struct {
|
||||
fi fs.FileInfo
|
||||
}
|
||||
|
||||
func (s subFsFileInfo) Name() string {
|
||||
return s.fi.Name()
|
||||
}
|
||||
|
||||
func (s subFsFileInfo) Size() int64 {
|
||||
return s.fi.Size()
|
||||
}
|
||||
|
||||
func (s subFsFileInfo) Mode() fs.FileMode {
|
||||
return s.fi.Mode()
|
||||
}
|
||||
|
||||
func (s subFsFileInfo) ModTime() time.Time {
|
||||
return s.fi.ModTime()
|
||||
}
|
||||
|
||||
func (s subFsFileInfo) IsDir() bool {
|
||||
return s.fi.IsDir()
|
||||
}
|
||||
|
||||
func (s subFsFileInfo) Sys() any {
|
||||
return s.fi.Sys()
|
||||
}
|
||||
|
||||
var _ fs.FileInfo = (*subFsFileInfo)(nil)
|
||||
@@ -0,0 +1,27 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_NewSubFS(t *testing.T) {
|
||||
f := os.DirFS("test-fixtures/zip-fs")
|
||||
f = newSubFS(f, "github.com/someorg/somepkg@version")
|
||||
var names []string
|
||||
err := fs.WalkDir(f, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
names = append(names, path)
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
expected := []string{
|
||||
".",
|
||||
"a-file",
|
||||
"subdir",
|
||||
"subdir/subfile",
|
||||
}
|
||||
require.Equal(t, expected, names)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2022
|
||||
Acme, inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
THIS SOFTWARE IS PROVIDED BY [Name of Organization] “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL [Name of Organisation] BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+1
@@ -0,0 +1 @@
|
||||
a file
|
||||
+1
@@ -0,0 +1 @@
|
||||
another file
|
||||
@@ -46,6 +46,14 @@ func parseCabalFreeze(_ source.FileResolver, _ *generic.Environment, reader sour
|
||||
fields := strings.Split(line, " ==")
|
||||
|
||||
pkgName, pkgVersion := fields[0], fields[1]
|
||||
pkgs = append(pkgs, newPackage(pkgName, pkgVersion, nil, reader.Location))
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
newPackage(
|
||||
pkgName,
|
||||
pkgVersion,
|
||||
nil,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,10 +62,18 @@ func parseStackLock(_ source.FileResolver, _ *generic.Environment, reader source
|
||||
|
||||
for _, pack := range lockFile.Packages {
|
||||
pkgName, pkgVersion, pkgHash := parseStackPackageEncoding(pack.Completed.Hackage)
|
||||
pkgs = append(pkgs, newPackage(pkgName, pkgVersion, &pkg.HackageMetadata{
|
||||
PkgHash: pkgHash,
|
||||
SnapshotURL: snapshotURL,
|
||||
}, reader.Location))
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
newPackage(
|
||||
pkgName,
|
||||
pkgVersion,
|
||||
&pkg.HackageMetadata{
|
||||
PkgHash: pkgHash,
|
||||
SnapshotURL: snapshotURL,
|
||||
},
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
|
||||
@@ -34,9 +34,17 @@ func parseStackYaml(_ source.FileResolver, _ *generic.Environment, reader source
|
||||
var pkgs []pkg.Package
|
||||
for _, dep := range stackFile.ExtraDeps {
|
||||
pkgName, pkgVersion, pkgHash := parseStackPackageEncoding(dep)
|
||||
pkgs = append(pkgs, newPackage(pkgName, pkgVersion, &pkg.HackageMetadata{
|
||||
PkgHash: pkgHash,
|
||||
}, reader.Location))
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
newPackage(
|
||||
pkgName,
|
||||
pkgVersion,
|
||||
&pkg.HackageMetadata{
|
||||
PkgHash: pkgHash,
|
||||
},
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
|
||||
@@ -108,7 +108,7 @@ func (a archiveFilename) extension() string {
|
||||
|
||||
func (a archiveFilename) pkgType() pkg.Type {
|
||||
switch strings.ToLower(a.extension()) {
|
||||
case "jar", "war", "ear", "lpkg", "par", "sar":
|
||||
case "jar", "war", "ear", "lpkg", "par", "sar", "nar":
|
||||
return pkg.JavaPkg
|
||||
case "jpi", "hpi":
|
||||
return pkg.JenkinsPluginPkg
|
||||
|
||||
@@ -79,6 +79,13 @@ func TestExtractInfoFromJavaArchiveFilename(t *testing.T) {
|
||||
name: "pkg-extra-field-maven",
|
||||
ty: pkg.JavaPkg,
|
||||
},
|
||||
{
|
||||
filename: "pkg-extra-field-maven-4.3.2-rc1.nar",
|
||||
version: "4.3.2-rc1",
|
||||
extension: "nar",
|
||||
name: "pkg-extra-field-maven",
|
||||
ty: pkg.JavaPkg,
|
||||
},
|
||||
{
|
||||
filename: "/some/path/pkg-extra-field-maven-4.3.2-rc1.jpi",
|
||||
version: "4.3.2-rc1",
|
||||
|
||||
@@ -24,6 +24,7 @@ var archiveFormatGlobs = []string{
|
||||
"**/*.ear",
|
||||
"**/*.par",
|
||||
"**/*.sar",
|
||||
"**/*.nar",
|
||||
"**/*.jpi",
|
||||
"**/*.hpi",
|
||||
"**/*.lpkg", // Zip-compressed package used to deploy applications
|
||||
@@ -185,11 +186,13 @@ func (j *archiveParser) discoverMainPackage() (*pkg.Package, error) {
|
||||
}
|
||||
|
||||
return &pkg.Package{
|
||||
Name: selectName(manifest, j.fileInfo),
|
||||
Version: selectVersion(manifest, j.fileInfo),
|
||||
Licenses: selectLicense(manifest),
|
||||
Language: pkg.Java,
|
||||
Locations: source.NewLocationSet(j.location),
|
||||
Name: selectName(manifest, j.fileInfo),
|
||||
Version: selectVersion(manifest, j.fileInfo),
|
||||
Licenses: selectLicense(manifest),
|
||||
Language: pkg.Java,
|
||||
Locations: source.NewLocationSet(
|
||||
j.location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
Type: j.fileInfo.pkgType(),
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
Metadata: pkg.JavaMetadata{
|
||||
@@ -379,9 +382,11 @@ func newPackageFromMavenData(pomProperties pkg.PomProperties, pomProject *pkg.Po
|
||||
|
||||
// discovered props = new package
|
||||
p := pkg.Package{
|
||||
Name: pomProperties.ArtifactID,
|
||||
Version: pomProperties.Version,
|
||||
Locations: source.NewLocationSet(location),
|
||||
Name: pomProperties.ArtifactID,
|
||||
Version: pomProperties.Version,
|
||||
Locations: source.NewLocationSet(
|
||||
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
Language: pkg.Java,
|
||||
Type: pomProperties.PkgTypeIndicated(),
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
|
||||
@@ -159,10 +159,39 @@ func TestParseJar(t *testing.T) {
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Manifest-Version": "1.0",
|
||||
"Main-Class": "hello.HelloWorld",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"joda-time": {
|
||||
Name: "joda-time",
|
||||
Version: "2.2",
|
||||
PURL: "pkg:maven/joda-time/joda-time@2.2",
|
||||
Language: pkg.Java,
|
||||
Type: pkg.JavaPkg,
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
Metadata: pkg.JavaMetadata{
|
||||
// ensure that nested packages with different names than that of the parent are appended as
|
||||
// a suffix on the virtual path
|
||||
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar:joda-time",
|
||||
PomProperties: &pkg.PomProperties{
|
||||
Path: "META-INF/maven/joda-time/joda-time/pom.properties",
|
||||
GroupID: "joda-time",
|
||||
ArtifactID: "joda-time",
|
||||
Version: "2.2",
|
||||
},
|
||||
PomProject: &pkg.PomProject{
|
||||
Path: "META-INF/maven/joda-time/joda-time/pom.xml",
|
||||
GroupID: "joda-time",
|
||||
ArtifactID: "joda-time",
|
||||
Version: "2.2",
|
||||
Name: "Joda time",
|
||||
Description: "Date and time library to replace JDK date handling",
|
||||
URL: "http://joda-time.sourceforge.net",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -31,3 +31,11 @@ func NewJavaPomCataloger() *generic.Cataloger {
|
||||
return generic.NewCataloger("java-pom-cataloger").
|
||||
WithParserByGlobs(parserPomXML, "**/pom.xml")
|
||||
}
|
||||
|
||||
// NewJavaGradleLockfileCataloger returns a cataloger capable of parsing
|
||||
// dependencies from a gradle.lockfile file.
|
||||
// older versions of lockfiles aren't supported yet
|
||||
func NewJavaGradleLockfileCataloger() *generic.Cataloger {
|
||||
return generic.NewCataloger("java-gradle-lockfile-cataloger").
|
||||
WithParserByGlobs(parseGradleLockfile, gradleLockfileGlob)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ func Test_ArchiveCataloger_Globs(t *testing.T) {
|
||||
"java-archives/example.ear",
|
||||
"java-archives/example.par",
|
||||
"java-archives/example.sar",
|
||||
"java-archives/example.nar",
|
||||
"java-archives/example.jpi",
|
||||
"java-archives/example.hpi",
|
||||
"java-archives/example.lpkg",
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package java
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
const gradleLockfileGlob = "**/gradle.lockfile*"
|
||||
|
||||
// Dependency represents a single dependency in the gradle.lockfile file
|
||||
type LockfileDependency struct {
|
||||
Group string
|
||||
Name string
|
||||
Version string
|
||||
}
|
||||
|
||||
func parseGradleLockfile(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
var pkgs []pkg.Package
|
||||
|
||||
// Create a new scanner to read the file
|
||||
scanner := bufio.NewScanner(reader)
|
||||
|
||||
// Create slices to hold the dependencies and plugins
|
||||
dependencies := []LockfileDependency{}
|
||||
|
||||
// Loop over all lines in the file
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
// Trim leading and trailing whitespace from the line
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
groupNameVersion := line
|
||||
groupNameVersion = strings.Split(groupNameVersion, "=")[0]
|
||||
parts := strings.Split(groupNameVersion, ":")
|
||||
|
||||
// we have a version directly specified
|
||||
if len(parts) == 3 {
|
||||
// Create a new Dependency struct and add it to the dependencies slice
|
||||
dep := LockfileDependency{Group: parts[0], Name: parts[1], Version: parts[2]}
|
||||
dependencies = append(dependencies, dep)
|
||||
}
|
||||
}
|
||||
// map the dependencies
|
||||
for _, dep := range dependencies {
|
||||
mappedPkg := pkg.Package{
|
||||
Name: dep.Name,
|
||||
Version: dep.Version,
|
||||
Locations: source.NewLocationSet(
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
Language: pkg.Java,
|
||||
Type: pkg.JavaPkg,
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
}
|
||||
pkgs = append(pkgs, mappedPkg)
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package java
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func Test_parserGradleLockfile(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected []pkg.Package
|
||||
}{
|
||||
{
|
||||
input: "test-fixtures/gradle/gradle.lockfile",
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "hamcrest-core",
|
||||
Version: "1.3",
|
||||
Language: pkg.Java,
|
||||
Type: pkg.JavaPkg,
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
},
|
||||
{
|
||||
Name: "joda-time",
|
||||
Version: "2.2",
|
||||
Language: pkg.Java,
|
||||
Type: pkg.JavaPkg,
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
},
|
||||
{
|
||||
Name: "junit",
|
||||
Version: "4.12",
|
||||
Language: pkg.Java,
|
||||
Type: pkg.JavaPkg,
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
for i := range test.expected {
|
||||
test.expected[i].Locations.Add(source.NewLocation(test.input))
|
||||
}
|
||||
pkgtest.TestFileParser(t, test.input, parseGradleLockfile, test.expected, nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,11 @@ func parserPomXML(_ source.FileResolver, _ *generic.Environment, reader source.L
|
||||
|
||||
var pkgs []pkg.Package
|
||||
for _, dep := range pom.Dependencies {
|
||||
p := newPackageFromPom(pom, dep, reader.Location)
|
||||
p := newPackageFromPom(
|
||||
pom,
|
||||
dep,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
if p.Name == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
example archive
|
||||
@@ -0,0 +1 @@
|
||||
.gradle
|
||||
@@ -0,0 +1,58 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'eclipse'
|
||||
id 'application'
|
||||
}
|
||||
|
||||
mainClassName = 'hello.HelloWorld'
|
||||
|
||||
dependencyLocking {
|
||||
lockAllConfigurations()
|
||||
}
|
||||
// tag::repositories[]
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
// end::repositories[]
|
||||
|
||||
// tag::dependencies[]
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
dependencies {
|
||||
implementation "joda-time:joda-time:2.2"
|
||||
testImplementation "junit:junit:4.12"
|
||||
}
|
||||
// end::dependencies[]
|
||||
|
||||
// tag::jar[]
|
||||
jar {
|
||||
archivesBaseName = 'example-java-app-gradle'
|
||||
version = '0.1.0'
|
||||
manifest {
|
||||
attributes(
|
||||
'Main-Class': 'hello.HelloWorld'
|
||||
)
|
||||
}
|
||||
from {
|
||||
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
||||
}
|
||||
}
|
||||
// end::jar[]
|
||||
|
||||
// tag::wrapper[]
|
||||
// end::wrapper[]
|
||||
|
||||
// to invoke: gradle resolveAndLockAll --write-locks
|
||||
tasks.register('resolveAndLockAll') {
|
||||
notCompatibleWithConfigurationCache("Filters configurations at execution time")
|
||||
doFirst {
|
||||
assert gradle.startParameter.writeDependencyLocks
|
||||
}
|
||||
doLast {
|
||||
configurations.findAll {
|
||||
// Add any custom filtering on the configurations to be resolved
|
||||
it.canBeResolved
|
||||
}.each { it.resolve() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
joda-time:joda-time:2.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
junit:junit:4.12=testCompileClasspath,testRuntimeClasspath
|
||||
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath
|
||||
empty=annotationProcessor,testAnnotationProcessor
|
||||
@@ -4,7 +4,7 @@ set -uxe
|
||||
# note: this can be easily done in a 1-liner, however circle CI does NOT allow volume mounts from the host in docker executors (since they are on remote hosts, where the host files are inaccessible)
|
||||
|
||||
PKGSDIR=$1
|
||||
CTRID=$(docker create -u "$(id -u):$(id -g)" -v /example-java-app -w /example-java-app gradle:6.8.3-jdk gradle build)
|
||||
CTRID=$(docker create -u "$(id -u):$(id -g)" -v /example-java-app -w /example-java-app gradle:8.0.2-jdk gradle build)
|
||||
|
||||
function cleanup() {
|
||||
docker rm "${CTRID}"
|
||||
|
||||
@@ -1,31 +1,58 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'application'
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'eclipse'
|
||||
id 'application'
|
||||
}
|
||||
|
||||
mainClassName = 'hello.HelloWorld'
|
||||
|
||||
dependencyLocking {
|
||||
lockAllConfigurations()
|
||||
}
|
||||
// tag::repositories[]
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
// end::repositories[]
|
||||
|
||||
// tag::jar[]
|
||||
jar {
|
||||
baseName = 'example-java-app-gradle'
|
||||
version = '0.1.0'
|
||||
}
|
||||
// end::jar[]
|
||||
|
||||
// tag::dependencies[]
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
dependencies {
|
||||
compile "joda-time:joda-time:2.2"
|
||||
testCompile "junit:junit:4.12"
|
||||
implementation "joda-time:joda-time:2.2"
|
||||
testImplementation "junit:junit:4.12"
|
||||
}
|
||||
// end::dependencies[]
|
||||
|
||||
// tag::jar[]
|
||||
jar {
|
||||
archivesBaseName = 'example-java-app-gradle'
|
||||
version = '0.1.0'
|
||||
manifest {
|
||||
attributes(
|
||||
'Main-Class': 'hello.HelloWorld'
|
||||
)
|
||||
}
|
||||
from {
|
||||
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
||||
}
|
||||
}
|
||||
// end::jar[]
|
||||
|
||||
// tag::wrapper[]
|
||||
// end::wrapper[]
|
||||
// end::wrapper[]
|
||||
|
||||
// to invoke: gradle resolveAndLockAll --write-locks
|
||||
tasks.register('resolveAndLockAll') {
|
||||
notCompatibleWithConfigurationCache("Filters configurations at execution time")
|
||||
doFirst {
|
||||
assert gradle.startParameter.writeDependencyLocks
|
||||
}
|
||||
doLast {
|
||||
configurations.findAll {
|
||||
// Add any custom filtering on the configurations to be resolved
|
||||
it.canBeResolved
|
||||
}.each { it.resolve() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
joda-time:joda-time:2.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
junit:junit:4.12=testCompileClasspath,testRuntimeClasspath
|
||||
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath
|
||||
empty=annotationProcessor,testAnnotationProcessor
|
||||
@@ -28,13 +28,14 @@ func newPackageJSONPackage(u packageJSON, locations ...source.Location) pkg.Pack
|
||||
Type: pkg.NpmPkg,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: u.Name,
|
||||
Version: u.Version,
|
||||
Author: u.Author.AuthorString(),
|
||||
Homepage: u.Homepage,
|
||||
URL: u.Repository.URL,
|
||||
Licenses: licenses,
|
||||
Private: u.Private,
|
||||
Name: u.Name,
|
||||
Version: u.Version,
|
||||
Author: u.Author.AuthorString(),
|
||||
Homepage: u.Homepage,
|
||||
URL: u.Repository.URL,
|
||||
Licenses: licenses,
|
||||
Private: u.Private,
|
||||
Description: u.Description,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -65,7 +66,7 @@ func newPackageLockV1Package(resolver source.FileResolver, location source.Locat
|
||||
pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Locations: source.NewLocationSet(location),
|
||||
Locations: source.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(name, version),
|
||||
Language: pkg.JavaScript,
|
||||
Type: pkg.NpmPkg,
|
||||
@@ -88,7 +89,7 @@ func newPackageLockV2Package(resolver source.FileResolver, location source.Locat
|
||||
pkg.Package{
|
||||
Name: name,
|
||||
Version: u.Version,
|
||||
Locations: source.NewLocationSet(location),
|
||||
Locations: source.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(name, u.Version),
|
||||
Language: pkg.JavaScript,
|
||||
Type: pkg.NpmPkg,
|
||||
@@ -106,7 +107,7 @@ func newPnpmPackage(resolver source.FileResolver, location source.Location, name
|
||||
pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Locations: source.NewLocationSet(location),
|
||||
Locations: source.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(name, version),
|
||||
Language: pkg.JavaScript,
|
||||
Type: pkg.NpmPkg,
|
||||
@@ -121,7 +122,7 @@ func newYarnLockPackage(resolver source.FileResolver, location source.Location,
|
||||
pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Locations: source.NewLocationSet(location),
|
||||
Locations: source.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(name, version),
|
||||
Language: pkg.JavaScript,
|
||||
Type: pkg.NpmPkg,
|
||||
|
||||
@@ -68,7 +68,10 @@ func parsePackageJSON(_ source.FileResolver, _ *generic.Environment, reader sour
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
pkgs = append(pkgs, newPackageJSONPackage(p, reader.Location))
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
newPackageJSONPackage(p, reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
)
|
||||
}
|
||||
|
||||
pkg.Sort(pkgs)
|
||||
|
||||
@@ -26,12 +26,13 @@ func TestParsePackageJSON(t *testing.T) {
|
||||
Language: pkg.JavaScript,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"Artistic-2.0"},
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"Artistic-2.0"},
|
||||
Description: "a package manager for JavaScript",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -46,12 +47,13 @@ func TestParsePackageJSON(t *testing.T) {
|
||||
Language: pkg.JavaScript,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"ISC"},
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"ISC"},
|
||||
Description: "a package manager for JavaScript",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -66,12 +68,13 @@ func TestParsePackageJSON(t *testing.T) {
|
||||
Language: pkg.JavaScript,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"MIT", "Apache-2.0"},
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"MIT", "Apache-2.0"},
|
||||
Description: "a package manager for JavaScript",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -86,12 +89,13 @@ func TestParsePackageJSON(t *testing.T) {
|
||||
Language: pkg.JavaScript,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: nil,
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: nil,
|
||||
Description: "a package manager for JavaScript",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -106,12 +110,13 @@ func TestParsePackageJSON(t *testing.T) {
|
||||
Language: pkg.JavaScript,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{},
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{},
|
||||
Description: "a package manager for JavaScript",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -126,12 +131,13 @@ func TestParsePackageJSON(t *testing.T) {
|
||||
Language: pkg.JavaScript,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"Artistic-2.0"},
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"Artistic-2.0"},
|
||||
Description: "a package manager for JavaScript",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -146,12 +152,13 @@ func TestParsePackageJSON(t *testing.T) {
|
||||
Language: pkg.JavaScript,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: "function-bind",
|
||||
Version: "1.1.1",
|
||||
Author: "Raynos <raynos2@gmail.com>",
|
||||
Homepage: "https://github.com/Raynos/function-bind",
|
||||
URL: "git://github.com/Raynos/function-bind.git",
|
||||
Licenses: []string{"MIT"},
|
||||
Name: "function-bind",
|
||||
Version: "1.1.1",
|
||||
Author: "Raynos <raynos2@gmail.com>",
|
||||
Homepage: "https://github.com/Raynos/function-bind",
|
||||
URL: "git://github.com/Raynos/function-bind.git",
|
||||
Licenses: []string{"MIT"},
|
||||
Description: "Implementation of Function.prototype.bind",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -166,13 +173,14 @@ func TestParsePackageJSON(t *testing.T) {
|
||||
Language: pkg.JavaScript,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"Artistic-2.0"},
|
||||
Private: true,
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: []string{"Artistic-2.0"},
|
||||
Private: true,
|
||||
Description: "a package manager for JavaScript",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -113,7 +113,10 @@ func parsePackageLock(resolver source.FileResolver, _ *generic.Environment, read
|
||||
name = pkgMeta.Name
|
||||
}
|
||||
|
||||
pkgs = append(pkgs, newPackageLockV2Package(resolver, reader.Location, getNameFromPath(name), pkgMeta))
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
newPackageLockV2Package(resolver, reader.Location, getNameFromPath(name), pkgMeta),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Package kernel provides a concrete Cataloger implementation for linux kernel and module files.
|
||||
*/
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/go-multierror"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
var _ pkg.Cataloger = (*LinuxKernelCataloger)(nil)
|
||||
|
||||
type LinuxCatalogerConfig struct {
|
||||
CatalogModules bool
|
||||
}
|
||||
|
||||
type LinuxKernelCataloger struct {
|
||||
cfg LinuxCatalogerConfig
|
||||
}
|
||||
|
||||
func DefaultLinuxCatalogerConfig() LinuxCatalogerConfig {
|
||||
return LinuxCatalogerConfig{
|
||||
CatalogModules: true,
|
||||
}
|
||||
}
|
||||
|
||||
var kernelArchiveGlobs = []string{
|
||||
"**/kernel",
|
||||
"**/kernel-*",
|
||||
"**/vmlinux",
|
||||
"**/vmlinux-*",
|
||||
"**/vmlinuz",
|
||||
"**/vmlinuz-*",
|
||||
}
|
||||
|
||||
var kernelModuleGlobs = []string{
|
||||
"**/lib/modules/**/*.ko",
|
||||
}
|
||||
|
||||
// NewLinuxKernelCataloger returns a new kernel files cataloger object.
|
||||
func NewLinuxKernelCataloger(cfg LinuxCatalogerConfig) *LinuxKernelCataloger {
|
||||
return &LinuxKernelCataloger{
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (l LinuxKernelCataloger) Name() string {
|
||||
return "linux-kernel-cataloger"
|
||||
}
|
||||
|
||||
func (l LinuxKernelCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
var allPackages []pkg.Package
|
||||
var allRelationships []artifact.Relationship
|
||||
var errs error
|
||||
|
||||
kernelPackages, kernelRelationships, err := generic.NewCataloger(l.Name()).WithParserByGlobs(parseLinuxKernelFile, kernelArchiveGlobs...).Catalog(resolver)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
}
|
||||
|
||||
allRelationships = append(allRelationships, kernelRelationships...)
|
||||
allPackages = append(allPackages, kernelPackages...)
|
||||
|
||||
if l.cfg.CatalogModules {
|
||||
modulePackages, moduleRelationships, err := generic.NewCataloger(l.Name()).WithParserByGlobs(parseLinuxKernelModuleFile, kernelModuleGlobs...).Catalog(resolver)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
}
|
||||
|
||||
allPackages = append(allPackages, modulePackages...)
|
||||
|
||||
moduleToKernelRelationships := createKernelToModuleRelationships(kernelPackages, modulePackages)
|
||||
allRelationships = append(allRelationships, moduleRelationships...)
|
||||
allRelationships = append(allRelationships, moduleToKernelRelationships...)
|
||||
}
|
||||
|
||||
return allPackages, allRelationships, errs
|
||||
}
|
||||
|
||||
func createKernelToModuleRelationships(kernelPackages, modulePackages []pkg.Package) []artifact.Relationship {
|
||||
// organize kernel and module packages by kernel version
|
||||
kernelPackagesByVersion := make(map[string][]*pkg.Package)
|
||||
for idx, p := range kernelPackages {
|
||||
kernelPackagesByVersion[p.Version] = append(kernelPackagesByVersion[p.Version], &kernelPackages[idx])
|
||||
}
|
||||
|
||||
modulesByKernelVersion := make(map[string][]*pkg.Package)
|
||||
for idx, p := range modulePackages {
|
||||
m, ok := p.Metadata.(pkg.LinuxKernelModuleMetadata)
|
||||
if !ok {
|
||||
log.Debug("linux-kernel-module package found without metadata: %s@%s", p.Name, p.Version)
|
||||
continue
|
||||
}
|
||||
modulesByKernelVersion[m.KernelVersion] = append(modulesByKernelVersion[m.KernelVersion], &modulePackages[idx])
|
||||
}
|
||||
|
||||
// create relationships between kernel and modules: [module] --(depends on)--> [kernel]
|
||||
// since we try to use singular directions for relationships, we'll use "dependency of" here instead:
|
||||
// [kernel] --(dependency of)--> [module]
|
||||
var moduleToKernelRelationships []artifact.Relationship
|
||||
for kernelVersion, modules := range modulesByKernelVersion {
|
||||
kps, ok := kernelPackagesByVersion[kernelVersion]
|
||||
if !ok {
|
||||
// it's ok if there is a module that has no installed kernel...
|
||||
continue
|
||||
}
|
||||
|
||||
// we don't know which kernel is the "right" one, so we'll create a relationship for each one
|
||||
for _, kp := range kps {
|
||||
for _, mp := range modules {
|
||||
moduleToKernelRelationships = append(moduleToKernelRelationships, artifact.Relationship{
|
||||
// note: relationships should have Package objects, not pointers
|
||||
From: *kp,
|
||||
To: *mp,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return moduleToKernelRelationships
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func Test_KernelCataloger(t *testing.T) {
|
||||
kernelPkg := pkg.Package{
|
||||
Name: "linux-kernel",
|
||||
Version: "6.0.7-301.fc37.x86_64",
|
||||
FoundBy: "linux-kernel-cataloger",
|
||||
Locations: source.NewLocationSet(
|
||||
source.NewVirtualLocation(
|
||||
"/lib/modules/6.0.7-301.fc37.x86_64/vmlinuz",
|
||||
"/lib/modules/6.0.7-301.fc37.x86_64/vmlinuz",
|
||||
),
|
||||
),
|
||||
Type: pkg.LinuxKernelPkg,
|
||||
PURL: "pkg:generic/linux-kernel@6.0.7-301.fc37.x86_64",
|
||||
MetadataType: pkg.LinuxKernelMetadataType,
|
||||
Metadata: pkg.LinuxKernelMetadata{
|
||||
Name: "",
|
||||
Architecture: "x86",
|
||||
Version: "6.0.7-301.fc37.x86_64",
|
||||
ExtendedVersion: "6.0.7-301.fc37.x86_64 (mockbuild@bkernel01.iad2.fedoraproject.org) #1 SMP PREEMPT_DYNAMIC Fri Nov 4 18:35:48 UTC 2022",
|
||||
BuildTime: "",
|
||||
Author: "",
|
||||
Format: "bzImage",
|
||||
RWRootFS: false,
|
||||
SwapDevice: 0,
|
||||
RootDevice: 0,
|
||||
VideoMode: "Video mode 65535",
|
||||
},
|
||||
}
|
||||
|
||||
kernelModulePkg := pkg.Package{
|
||||
Name: "ttynull",
|
||||
Version: "",
|
||||
FoundBy: "linux-kernel-cataloger",
|
||||
Locations: source.NewLocationSet(
|
||||
source.NewVirtualLocation("/lib/modules/6.0.7-301.fc37.x86_64/kernel/drivers/tty/ttynull.ko",
|
||||
"/lib/modules/6.0.7-301.fc37.x86_64/kernel/drivers/tty/ttynull.ko",
|
||||
),
|
||||
),
|
||||
Licenses: []string{
|
||||
"GPL v2",
|
||||
},
|
||||
Type: pkg.LinuxKernelModulePkg,
|
||||
PURL: "pkg:generic/ttynull",
|
||||
MetadataType: pkg.LinuxKernelModuleMetadataType,
|
||||
Metadata: pkg.LinuxKernelModuleMetadata{
|
||||
Name: "ttynull",
|
||||
Version: "",
|
||||
SourceVersion: "",
|
||||
License: "GPL v2",
|
||||
Path: "/lib/modules/6.0.7-301.fc37.x86_64/kernel/drivers/tty/ttynull.ko",
|
||||
Description: "",
|
||||
KernelVersion: "6.0.7-301.fc37.x86_64",
|
||||
VersionMagic: "6.0.7-301.fc37.x86_64 SMP preempt mod_unload ",
|
||||
Parameters: map[string]pkg.LinuxKernelModuleParameter{},
|
||||
},
|
||||
}
|
||||
|
||||
expectedPkgs := []pkg.Package{
|
||||
kernelPkg,
|
||||
kernelModulePkg,
|
||||
}
|
||||
expectedRelationships := []artifact.Relationship{
|
||||
{
|
||||
From: kernelPkg,
|
||||
To: kernelModulePkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
}
|
||||
|
||||
pkgtest.NewCatalogTester().
|
||||
WithImageResolver(t, "image-kernel-and-modules").
|
||||
IgnoreLocationLayer().
|
||||
Expects(expectedPkgs, expectedRelationships).
|
||||
TestCataloger(t,
|
||||
NewLinuxKernelCataloger(
|
||||
LinuxCatalogerConfig{
|
||||
CatalogModules: true,
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user