mirror of
https://github.com/anchore/syft.git
synced 2026-10-12 22:27:22 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc2c0e57a0 | ||
|
|
5253da4b36 | ||
|
|
c0b547bdb2 | ||
|
|
cffcaf5984 | ||
|
|
7f9edf346a | ||
|
|
a644a45ef4 | ||
|
|
283db88dc4 | ||
|
|
03e193e577 | ||
|
|
069aa68b63 | ||
|
|
9240860f44 | ||
|
|
4231f38fa2 | ||
|
|
752b03b2d6 | ||
|
|
99c3339810 | ||
|
|
f4734d28b3 | ||
|
|
6ef3e45ffc | ||
|
|
ee0a1d172c | ||
|
|
b9b3ccecf9 | ||
|
|
95271fb10d | ||
|
|
93d2d57cd3 | ||
|
|
7cd3201fe9 | ||
|
|
c7cf8b0b26 | ||
|
|
44a6e00f7a | ||
|
|
6c8102bf28 | ||
|
|
7789506dc6 | ||
|
|
fa03723617 | ||
|
|
2946813a74 |
@@ -29,7 +29,7 @@ notarize() {
|
||||
fi
|
||||
|
||||
# install gon
|
||||
which gon || (brew tap mitchellh/gon && brew install mitchellh/gon/gon)
|
||||
which gon || (go install github.com/mitchellh/gon/cmd/gon@latest)
|
||||
|
||||
# create config (note: json via stdin with gon is broken, can only use HCL from file)
|
||||
hcl_file=$(mktemp).hcl
|
||||
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
- "v*"
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.17.x"
|
||||
GO_VERSION: "1.18.x"
|
||||
|
||||
jobs:
|
||||
quality-gate:
|
||||
|
||||
@@ -7,7 +7,8 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.17.x"
|
||||
GO_VERSION: "1.18.x"
|
||||
GO_STABLE_VERSION: true
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -19,6 +20,7 @@ jobs:
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
stable: ${{ env.GO_STABLE_VERSION }}
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -56,6 +58,7 @@ jobs:
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
stable: ${{ env.GO_STABLE_VERSION }}
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -92,6 +95,16 @@ jobs:
|
||||
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: Build cache key for go binary test-fixture blobs (for unit tests)
|
||||
run: make go-binaries-fingerprint
|
||||
|
||||
- name: Restore Go binary test-fixture cache
|
||||
id: unit-go-binary-cache
|
||||
uses: actions/cache@v2.1.3
|
||||
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: Run unit tests
|
||||
run: make unit
|
||||
|
||||
@@ -108,6 +121,7 @@ jobs:
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
stable: ${{ env.GO_STABLE_VERSION }}
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -159,6 +173,7 @@ jobs:
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
stable: ${{ env.GO_STABLE_VERSION }}
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -231,6 +246,7 @@ jobs:
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
stable: ${{ env.GO_STABLE_VERSION }}
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -338,6 +354,7 @@ jobs:
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
stable: ${{ env.GO_STABLE_VERSION }}
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
||||
@@ -82,12 +82,6 @@ Date: Mon Aug 1 11:27:13 2020 -0400
|
||||
|
||||
[//]: # (TODO: PR title and description)
|
||||
|
||||
## Sign your commits
|
||||
|
||||
To ensure the authenticity and integrity of code contributions, **we require that all commits are signed**. Signing commits proves that your commits were truly created by you, as the holder of a private key.
|
||||
|
||||
Configuring git to sign your commits is a straightforward process. To get set up, see [GitHub's documentation on signing commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits).
|
||||
|
||||
## Test your changes
|
||||
|
||||
This project has a `Makefile` which includes many helpers running both unit and integration tests. Although PRs will have automatic checks for these, it is useful to run them locally, ensuring they pass before submitting changes. Ensure you've bootstrapped once before running tests:
|
||||
|
||||
@@ -106,7 +106,7 @@ $(TEMPDIR):
|
||||
.PHONY: bootstrap-tools
|
||||
bootstrap-tools: $(TEMPDIR)
|
||||
GO111MODULE=off GOBIN=$(shell realpath $(TEMPDIR)) go get -u golang.org/x/perf/cmd/benchstat
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.42.1
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.45.0
|
||||
curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.3.0
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/chronicle/main/install.sh | sh -s -- -b $(TEMPDIR)/ v0.3.0
|
||||
.github/scripts/goreleaser-install.sh -d -b $(TEMPDIR)/ v1.4.1
|
||||
@@ -122,7 +122,7 @@ bootstrap: $(RESULTSDIR) bootstrap-go bootstrap-tools ## Download and install al
|
||||
$(call title,Bootstrapping dependencies)
|
||||
|
||||
.PHONY: static-analysis
|
||||
static-analysis: lint check-go-mod-tidy check-licenses
|
||||
static-analysis: check-go-mod-tidy check-licenses lint
|
||||
|
||||
.PHONY: lint
|
||||
lint: ## Run gofmt + golangci lint checks
|
||||
@@ -214,6 +214,12 @@ java-packages-fingerprint:
|
||||
cd syft/pkg/cataloger/java/test-fixtures/java-builds && \
|
||||
make packages.fingerprint
|
||||
|
||||
.PHONY: go-binaries-fingerprint
|
||||
go-binaries-fingerprint:
|
||||
$(call title,Go binaries test fixture fingerprint)
|
||||
cd syft/pkg/cataloger/golang/test-fixtures/archs && \
|
||||
make binaries.fingerprint
|
||||
|
||||
.PHONY: fixtures
|
||||
fixtures:
|
||||
$(call title,Generating test fixtures)
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
|
||||
A CLI tool and Go library for generating a Software Bill of Materials (SBOM) from container images and filesystems. Exceptional for vulnerability detection when used with a scanner tool like [Grype](https://github.com/anchore/grype).
|
||||
|
||||
### Join our Virtual OSS Meetup!
|
||||
|
||||
You are invited to join us on March 23rd, 11AM-Noon PT for our virtual open source meetup.
|
||||
|
||||
Hosts Priyanka “Pinky” Ravi of Weaveworks and Dan Luhring from Anchore OSS will explore how open source project Flux is utilizing Syft-generated SBOMs to secure the software supply chain.
|
||||
|
||||
[Register here!](https://get.anchore.com/anchore-oss-meetup-mar-23-2022/)
|
||||
|
||||
### Join our community meetings!
|
||||
|
||||
- Calendar: https://calendar.google.com/calendar/u/0/r?cid=Y182OTM4dGt0MjRtajI0NnNzOThiaGtnM29qNEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t
|
||||
@@ -286,7 +294,11 @@ check-for-app-update: true
|
||||
# exclude:
|
||||
# - "/etc/**"
|
||||
# - "./out/**/*.json"
|
||||
exclude:
|
||||
exclude: []
|
||||
|
||||
# os and/or architecture to use when referencing container images (e.g. "windows/armv6" or "arm64")
|
||||
# same as --platform; SYFT_PLATFORM env var
|
||||
platform: ""
|
||||
|
||||
# cataloging packages is exposed through the packages and power-user subcommands
|
||||
package:
|
||||
|
||||
@@ -22,6 +22,8 @@ func formatAliases(ids ...sbom.FormatID) (aliases []string) {
|
||||
aliases = append(aliases, "cyclonedx-xml")
|
||||
case syft.CycloneDxJSONFormatID:
|
||||
aliases = append(aliases, "cyclonedx-json")
|
||||
case syft.GitHubID:
|
||||
aliases = append(aliases, "github", "github-json")
|
||||
default:
|
||||
aliases = append(aliases, string(id))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/anchore/syft
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/CycloneDX/cyclonedx-go v0.5.0
|
||||
@@ -9,11 +9,12 @@ require (
|
||||
github.com/adrg/xdg v0.2.1
|
||||
github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074
|
||||
github.com/anchore/client-go v0.0.0-20210222170800-9c70f9b80bcf
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
||||
github.com/anchore/go-rpmdb v0.0.0-20210914181456-a9c52348da63
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/packageurl-go v0.0.0-20210922164639-b3fa992ebd29
|
||||
github.com/anchore/stereoscope v0.0.0-20220307154759-8a5a70c227d3
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20220314153042-1bcd40e5206b
|
||||
github.com/anchore/stereoscope v0.0.0-20220323180633-4bdc70599cde
|
||||
github.com/antihax/optional v1.0.0
|
||||
github.com/bmatcuk/doublestar/v4 v4.0.2
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
@@ -33,7 +34,8 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/pelletier/go-toml v1.9.4
|
||||
github.com/pkg/profile v1.5.0
|
||||
github.com/scylladb/go-set v1.0.2
|
||||
// pinned to pull in 386 arch fix: https://github.com/scylladb/go-set/commit/cc7b2070d91ebf40d233207b633e28f5bd8f03a5
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e
|
||||
github.com/sergi/go-diff v1.2.0
|
||||
github.com/sigstore/sigstore v1.1.1-0.20220217212907-e48ca03a5ba7
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
@@ -171,7 +173,7 @@ require (
|
||||
github.com/hashicorp/go-uuid v1.0.2 // indirect
|
||||
github.com/hashicorp/go-version v1.4.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/vault/api v1.3.1 // indirect
|
||||
github.com/hashicorp/vault/api v1.4.1 // indirect
|
||||
github.com/hashicorp/vault/sdk v0.4.1 // indirect
|
||||
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
|
||||
@@ -106,9 +106,7 @@ contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj
|
||||
contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
|
||||
contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
|
||||
contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
|
||||
cuelang.org/go v0.4.2/go.mod h1:P09/R4UfAEzLkV9DXxwlxQnIZbkaT4uIhiEgs6Vsz2Q=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20211102141018-f7be0cbad29c/go.mod h1:WpB7kf89yJUETZxQnP1kgYPNwlT2jjdDYUCoxVggM3g=
|
||||
github.com/Antonboom/errname v0.1.5/go.mod h1:DugbBstvPFQbv/5uLcRRzfrNqKE9tVdVCqWCLp6Cifo=
|
||||
@@ -126,7 +124,6 @@ github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
|
||||
github.com/Azure/azure-sdk-for-go v59.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v60.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v60.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v61.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v61.5.0+incompatible h1:OSHSFeNm7D1InGsQrFjyN9hpxD5Ec60PdsWWudCpah4=
|
||||
github.com/Azure/azure-sdk-for-go v61.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0=
|
||||
@@ -227,18 +224,15 @@ github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:m
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
|
||||
github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8=
|
||||
github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I=
|
||||
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
|
||||
github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk=
|
||||
github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/ReneKroon/ttlcache/v2 v2.10.0/go.mod h1:mBxvsNY+BT8qLLd6CuAJubbKo6r0jh3nb5et22bbfGY=
|
||||
@@ -276,16 +270,18 @@ github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:C
|
||||
github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
|
||||
github.com/anchore/client-go v0.0.0-20210222170800-9c70f9b80bcf h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=
|
||||
github.com/anchore/client-go v0.0.0-20210222170800-9c70f9b80bcf/go.mod h1:FaODhIA06mxO1E6R32JE0TL1JWZZkmjRIAd4ULvHUKk=
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU=
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb/go.mod h1:DmTY2Mfcv38hsHbG78xMiTDdxFtkHpgYNVDPsF2TgHk=
|
||||
github.com/anchore/go-rpmdb v0.0.0-20210914181456-a9c52348da63 h1:C9W/LAydEz/qdUhx1MdjO9l8NEcFKYknkxDVyo9LAoM=
|
||||
github.com/anchore/go-rpmdb v0.0.0-20210914181456-a9c52348da63/go.mod h1:6qH8c6U/3CBVvDDDBZnPSTbTINq3cIdADUYTaVf75EM=
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0vW0nnNKJfJieyH/TZ9UYAnTZs5/gHTdAe8=
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZVsCYMrIZBpFxwV26CbsuoEh5muXD5I1Ods=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/packageurl-go v0.0.0-20210922164639-b3fa992ebd29 h1:K9LfnxwhqvihqU0+MF325FNy7fsKV9EGaUxdfR4gnWk=
|
||||
github.com/anchore/packageurl-go v0.0.0-20210922164639-b3fa992ebd29/go.mod h1:Oc1UkGaJwY6ND6vtAqPSlYrptKRJngHwkwB6W7l1uP0=
|
||||
github.com/anchore/stereoscope v0.0.0-20220307154759-8a5a70c227d3 h1:Kx2jlMdENAf4cVjYGYLI+fiavVhzhtmU89GUYDITJ1w=
|
||||
github.com/anchore/stereoscope v0.0.0-20220307154759-8a5a70c227d3/go.mod h1:XESZQTgFETDBatmyoet6XZ0zVknoIMDSAhj2INj2a5w=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20220314153042-1bcd40e5206b h1:YJWYt/6KQXR9JR46lLHrTTYi8rcye42tKcyjREA/hvA=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20220314153042-1bcd40e5206b/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
|
||||
github.com/anchore/stereoscope v0.0.0-20220323180633-4bdc70599cde h1:yOi6g1D2q3WwzID0QQyF+x9VkzUyGSJy3cEYbp7ZOyk=
|
||||
github.com/anchore/stereoscope v0.0.0-20220323180633-4bdc70599cde/go.mod h1:OVVJ4y/L26pspeeHNvNa7GeQfoLPWxJe13iODl9x5l4=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
@@ -435,7 +431,6 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR
|
||||
github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q=
|
||||
github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/bradleyfalzon/ghinstallation/v2 v2.0.3/go.mod h1:tlgi+JWCXnKFx/Y4WtnDbZEINo31N5bcvnCoqieefmk=
|
||||
github.com/bradleyjkemp/cupaloy/v2 v2.7.0 h1:AT0vOjO68RcLyenLCHOGZzSNiuto7ziqzq6Q1/3xzMQ=
|
||||
github.com/bradleyjkemp/cupaloy/v2 v2.7.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
|
||||
github.com/breml/bidichk v0.1.1/go.mod h1:zbfeitpevDUGI7V91Uzzuwrn4Vls8MoBMrwtt78jmso=
|
||||
@@ -445,8 +440,6 @@ github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8n
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
|
||||
github.com/bytecodealliance/wasmtime-go v0.31.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI=
|
||||
github.com/bytecodealliance/wasmtime-go v0.33.1/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI=
|
||||
github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
|
||||
github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw=
|
||||
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo=
|
||||
@@ -455,7 +448,6 @@ github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n
|
||||
github.com/cavaliercoder/badio v0.0.0-20160213150051-ce5280129e9e/go.mod h1:V284PjgVwSk4ETmz84rpu9ehpGg7swlIH8npP9k2bGw=
|
||||
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
|
||||
github.com/cavaliercoder/go-rpm v0.0.0-20200122174316-8cb9fd9c31a8/go.mod h1:AZIh1CCnMrcVm6afFf96PBvE2MRpWFco91z8ObJtgDY=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
|
||||
github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
|
||||
@@ -468,7 +460,6 @@ github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA
|
||||
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
|
||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
@@ -503,8 +494,6 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 h1:KwaoQzs/WeUxxJqiJsZ4euOly1Az/IgZXXSxlD/UBNk=
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/apd/v2 v2.0.1/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
||||
@@ -614,7 +603,6 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM=
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-oidc/v3 v3.1.0 h1:6avEvcdvTa1qYsOZ6I5PRkSYHzpTNWgKYmaJfaYbrRw=
|
||||
github.com/coreos/go-oidc/v3 v3.1.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
|
||||
@@ -624,7 +612,6 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
||||
github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a h1:W8b4lQ4tFF21aspRGoBuCNV6V2fFJBF+pm1J6OY8Lys=
|
||||
github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
@@ -632,7 +619,6 @@ github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzA
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
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.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
@@ -662,12 +648,8 @@ github.com/denis-tingajkin/go-header v0.4.2/go.mod h1:eLRHAVXzE5atsKAnNRDB90WHCF
|
||||
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
|
||||
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
|
||||
github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M=
|
||||
github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug=
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-gk v0.0.0-20140819190930-201884a44051/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E=
|
||||
github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E=
|
||||
github.com/dgryski/go-lttb v0.0.0-20180810165845-318fcdf10a77/go.mod h1:Va5MyIzkU0rAM92tn3hb3Anb7oz7KcnixF49+2wOMe4=
|
||||
@@ -720,7 +702,6 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/proto v1.6.15/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
@@ -768,7 +749,6 @@ github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
||||
@@ -849,14 +829,12 @@ github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX
|
||||
github.com/go-openapi/errors v0.20.1/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8=
|
||||
github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
@@ -886,7 +864,6 @@ github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pt
|
||||
github.com/go-openapi/runtime v0.21.0/go.mod h1:aQg+kaIQEn+A2CRSY1TxbM8+sT9g2V3aLc1FbIAnbbs=
|
||||
github.com/go-openapi/runtime v0.23.1 h1:/Drg9R96eMmgKJHVWZADz78XbE39/6QiIiB45mc+epo=
|
||||
github.com/go-openapi/runtime v0.23.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
|
||||
@@ -913,7 +890,6 @@ github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+W
|
||||
github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
|
||||
github.com/go-openapi/strfmt v0.21.2 h1:5NDNgadiX1Vhemth/TH4gCGopWSTdDjxl60H3B7f+os=
|
||||
github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
@@ -1110,7 +1086,6 @@ github.com/google/certificate-transparency-go v1.1.2-0.20210422104406-9f33727a7a
|
||||
github.com/google/certificate-transparency-go v1.1.2-0.20210512142713-bed466244fa6/go.mod h1:aF2dp7Dh81mY8Y/zpzyXps4fQW5zQbDu2CxfpJB6NkI=
|
||||
github.com/google/certificate-transparency-go v1.1.2 h1:4hE0GEId6NAW28dFpC+LrRGwQX5dtmXQGDbg8+/MZOM=
|
||||
github.com/google/certificate-transparency-go v1.1.2/go.mod h1:3OL+HKDqHPUfdKrHVQxO6T8nDLO0HF7LRTlkIWXaWvQ=
|
||||
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@@ -1128,14 +1103,10 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8
|
||||
github.com/google/go-containerregistry v0.7.0/go.mod h1:2zaoelrL0d08gGbpdP3LqyUuBmhWbpD6IOe2s9nLS2k=
|
||||
github.com/google/go-containerregistry v0.7.1-0.20211118220127-abdc633f8305/go.mod h1:6cMIl1RfryEiPzBE67OgtZdEiLWz4myqCQIiBMy3CsM=
|
||||
github.com/google/go-containerregistry v0.8.0/go.mod h1:wW5v71NHGnQyb4k+gSshjxidrC7lN33MdWEn+Mz9TsI=
|
||||
github.com/google/go-containerregistry v0.8.1-0.20220110151055-a61fd0a8e2bb/go.mod h1:wW5v71NHGnQyb4k+gSshjxidrC7lN33MdWEn+Mz9TsI=
|
||||
github.com/google/go-containerregistry v0.8.1-0.20220209165246-a44adc326839 h1:7PunQZxMao2q43If8gKj1JFRzapmhgny9NWwXY4PGa4=
|
||||
github.com/google/go-containerregistry v0.8.1-0.20220209165246-a44adc326839/go.mod h1:cwx3SjrH84Rh9VFJSIhPh43ovyOp3DCWgY3h8nWmdGQ=
|
||||
github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20220219142810-1571d7fdc46e/go.mod h1:m6nUV1MgElByyfWJCAKsEt+5s/BtU9ZLjyHDmoeAHcM=
|
||||
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20220128225446-c63684ed5f15/go.mod h1:juPcrnQFaTyH72YA4Lt2MwEFSGi3orvGXyzxzo+RLss=
|
||||
github.com/google/go-github/v27 v27.0.6/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0=
|
||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||
github.com/google/go-github/v39 v39.0.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
|
||||
github.com/google/go-github/v42 v42.0.0 h1:YNT0FwjPrEysRkLIiKuEfSvBPCGKphW5aS5PxwaoLec=
|
||||
github.com/google/go-github/v42 v42.0.0/go.mod h1:jgg/jvyI0YlDOM1/ps6XYh04HNQ3vKf0CVko62/EhRg=
|
||||
github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M=
|
||||
@@ -1180,7 +1151,6 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
|
||||
github.com/google/rpmpack v0.0.0-20210518075352-dc539ef4f2ea/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw=
|
||||
github.com/google/trillian v1.3.14-0.20210409160123-c5ea3abd4a41/go.mod h1:1dPv0CUjNQVFEDuAUFhZql16pw/VlPgaX8qj+g5pVzQ=
|
||||
@@ -1196,7 +1166,6 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
|
||||
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
|
||||
github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww=
|
||||
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
@@ -1300,7 +1269,6 @@ github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ3
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
@@ -1349,8 +1317,9 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
|
||||
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
|
||||
github.com/hashicorp/vault/api v1.3.0/go.mod h1:EabNQLI0VWbWoGlA+oBLC8PXmR9D60aUVgQGvangFWQ=
|
||||
github.com/hashicorp/vault/api v1.3.1 h1:pkDkcgTh47PRjY1NEFeofqR4W/HkNUi9qIakESO2aRM=
|
||||
github.com/hashicorp/vault/api v1.3.1/go.mod h1:QeJoWxMFt+MsuWcYhmwRLwKEXrjwAFFywzhptMsTIUw=
|
||||
github.com/hashicorp/vault/api v1.4.1 h1:mWLfPT0RhxBitjKr6swieCEP2v5pp/M//t70S3kMLRo=
|
||||
github.com/hashicorp/vault/api v1.4.1/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM=
|
||||
github.com/hashicorp/vault/sdk v0.3.0/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0=
|
||||
github.com/hashicorp/vault/sdk v0.4.1 h1:3SaHOJY687jY1fnB61PtL0cOkKItphrbLmux7T92HBo=
|
||||
github.com/hashicorp/vault/sdk v0.4.1/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0=
|
||||
@@ -1456,7 +1425,6 @@ github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
|
||||
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
@@ -1515,7 +1483,6 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
|
||||
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
@@ -1525,7 +1492,6 @@ github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
|
||||
github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
@@ -1583,11 +1549,9 @@ github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Cl
|
||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.17/go.mod h1:WgzbA6oji13JREwiNsRDNfl7jYdPnmz+VEuLrA+/48M=
|
||||
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
@@ -1651,7 +1615,6 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8=
|
||||
github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s=
|
||||
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de/go.mod h1:kJun4WP5gFuHZgRjZUWWuH1DTxCtxbHDOIJsudS8jzY=
|
||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
@@ -1719,7 +1682,6 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/open-policy-agent/opa v0.35.0/go.mod h1:xEmekKlk6/c+so5HF9wtPnGPXDfBuBsrMGhSHOHEF+U=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
@@ -1780,7 +1742,6 @@ github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhEC
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
@@ -1841,7 +1802,6 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8
|
||||
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
@@ -1863,7 +1823,6 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/protocolbuffers/txtpbfmt v0.0.0-20201118171849-f6a6b3f636fc/go.mod h1:KbKfKPy2I6ecOIGA9apfheFv14+P3RSmmQvshofQyMY=
|
||||
github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA=
|
||||
github.com/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg=
|
||||
github.com/pseudomuto/protoc-gen-doc v1.5.0/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg=
|
||||
@@ -1879,7 +1838,6 @@ github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:r
|
||||
github.com/qur/ar v0.0.0-20130629153254-282534b91770/go.mod h1:SjlYv2m9lpV0UW6K7lDqVJwEIIvSjaHbGk7nIfY8Hxw=
|
||||
github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
@@ -1897,7 +1855,6 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM=
|
||||
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
||||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
@@ -1920,8 +1877,9 @@ github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74 h1:sUNzanSKA9z/h
|
||||
github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74/go.mod h1:YlB8wFIZmFLZ1JllNBfSURzz52fBxbliNgYALk1UDmk=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
|
||||
github.com/scylladb/go-set v1.0.2 h1:SkvlMCKhP0wyyct6j+0IHJkBkSZL+TDzZ4E7f7BCcRE=
|
||||
github.com/scylladb/go-set v1.0.2/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs=
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ=
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.2.0/go.mod h1:eIjBmIP8LD2MLBL/DkQWayLiz006Q4p+hCu79rvWleY=
|
||||
@@ -1981,7 +1939,6 @@ github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4l
|
||||
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
|
||||
github.com/spdx/tools-golang v0.2.0 h1:KBNcw7xvVycRWeCWZK/5xQJA+plymW1+rTCs8ekJDro=
|
||||
github.com/spdx/tools-golang v0.2.0/go.mod h1:RO4Y3IFROJnz+43JKm1YOrbtgQNljW4gAPpA/sY2eqo=
|
||||
@@ -2144,7 +2101,6 @@ github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb h1:Yz6VVOcLuWLA
|
||||
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb/go.mod h1:nDi3BAC5nEbVbg+WSJDHLbjHv0ZToq8nMPA97XMxF3E=
|
||||
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
|
||||
github.com/withfig/autocomplete-tools/packages/cobra v0.0.0-20220122124547-31d3821a6898/go.mod h1:cKObXQ6PVFO7bHUd5jpApXvMIt55Ewz7UdMiC05ONxI=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
|
||||
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
|
||||
@@ -2171,7 +2127,6 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b/go.mod h1:HptNXiXVDcJjXe9SqMd0v2FsL9f8dz4GnXgltU6q/co=
|
||||
github.com/yeya24/promlinter v0.1.0/go.mod h1:rs5vtZzeBHqqMwXqFScncpCF6u06lezhZepno9AB1Oc=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/ysmood/goob v0.3.0/go.mod h1:S3lq113Y91y1UBf1wj1pFOxeahvfKkCk6mTWTWbDdWs=
|
||||
@@ -2205,7 +2160,6 @@ go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k=
|
||||
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 h1:1JFLBqwIgdyHN1ZtgjTBwO+blA6gVOmZurpiMEsETKo=
|
||||
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
@@ -2374,14 +2328,12 @@ golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220213190939-1e6e3497d506 h1:EuGTJDfeg/PGZJp3gq1K+14eSLFTsrj1eg8KQuiUyKg=
|
||||
golang.org/x/crypto v0.0.0-20220213190939-1e6e3497d506/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
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=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
@@ -2390,7 +2342,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
|
||||
golang.org/x/exp v0.0.0-20210126221216-84987778548c/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -2407,15 +2358,12 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPI
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
@@ -2500,7 +2448,6 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@@ -2722,7 +2669,6 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -2772,7 +2718,6 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
@@ -2795,7 +2740,6 @@ golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roY
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200612220849-54c614fe050c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
@@ -3156,7 +3100,6 @@ k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs=
|
||||
k8s.io/api v0.23.3 h1:KNrME8KHGr12Ozjf8ytOewKzZh6hl/hHUZeHddT3a38=
|
||||
k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ=
|
||||
k8s.io/apiextensions-apiserver v0.22.5/go.mod h1:tIXeZ0BrDxUb1PoAz+tgOz43Zi1Bp4BEEqVtUccMJbE=
|
||||
k8s.io/apimachinery v0.19.7/go.mod h1:6sRbGRAVY5DOCuZwB5XkqguBqpqLU6q/kOaOdk29z6Q=
|
||||
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
|
||||
k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
|
||||
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
|
||||
@@ -3193,7 +3136,6 @@ k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
|
||||
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4=
|
||||
k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
|
||||
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
|
||||
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||
@@ -3203,12 +3145,10 @@ k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20220127004650-9b3446523e65 h1:ONWS0Wgdg5wRiQIAui7L/023aC9+IxrIrydY7l8llsE=
|
||||
k8s.io/utils v0.0.0-20220127004650-9b3446523e65/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
knative.dev/hack v0.0.0-20220118141833-9b2ed8471e30/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
|
||||
knative.dev/hack/schema v0.0.0-20220224013837-e1785985d364/go.mod h1:ffjwmdcrH5vN3mPhO8RrF2KfNnbHeCE2C60A+2cv3U0=
|
||||
knative.dev/pkg v0.0.0-20220202132633-df430fa0dd96 h1:JU0DFa06CaUtwSkAY0b3j47ohEJLIYlpPPgNgbPHlAo=
|
||||
knative.dev/pkg v0.0.0-20220202132633-df430fa0dd96/go.mod h1:etVT7Tm8pSDf4RKhGk4r7j/hj3dNBpvT7bO6a6wpahs=
|
||||
mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=
|
||||
@@ -3229,7 +3169,6 @@ sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87J
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
|
||||
sigs.k8s.io/release-utils v0.4.1-0.20220207182343-6dadf2228617 h1:qbKzP8fFAdlnj4WqB9KrAuW4ply+bUQkdRlVrH4Jus0=
|
||||
sigs.k8s.io/release-utils v0.4.1-0.20220207182343-6dadf2228617/go.mod h1:t9pL38kZkTBVDcjL1y7ajrkNQFLiArVAjOVO0sxzFF0=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
|
||||
@@ -56,7 +56,7 @@ func (c *Client) Import(ctx context.Context, cfg ImportConfig) error {
|
||||
authedCtx := c.newRequestContext(ctxWithTimeout)
|
||||
|
||||
stage.Current = "starting session"
|
||||
startOperation, _, err := c.client.ImportsApi.CreateOperation(authedCtx)
|
||||
startOperation, createResponse, err := c.client.ImportsApi.CreateOperation(authedCtx)
|
||||
if err != nil {
|
||||
var detail = "no details given"
|
||||
var openAPIErr external.GenericOpenAPIError
|
||||
@@ -65,6 +65,8 @@ func (c *Client) Import(ctx context.Context, cfg ImportConfig) error {
|
||||
}
|
||||
return fmt.Errorf("unable to start import session: %w: %s", err, detail)
|
||||
}
|
||||
defer createResponse.Body.Close()
|
||||
|
||||
prog.N++
|
||||
sessionID := startOperation.Uuid
|
||||
|
||||
@@ -98,7 +100,7 @@ func (c *Client) Import(ctx context.Context, cfg ImportConfig) error {
|
||||
Force: optional.NewBool(cfg.OverwriteExistingUpload),
|
||||
}
|
||||
|
||||
_, _, err = c.client.ImagesApi.AddImage(authedCtx, imageModel, &opts)
|
||||
_, addResponse, err := c.client.ImagesApi.AddImage(authedCtx, imageModel, &opts)
|
||||
if err != nil {
|
||||
var detail = "no details given"
|
||||
var openAPIErr external.GenericOpenAPIError
|
||||
@@ -107,6 +109,8 @@ func (c *Client) Import(ctx context.Context, cfg ImportConfig) error {
|
||||
}
|
||||
return fmt.Errorf("unable to complete import session=%q: %w: %s", sessionID, err, detail)
|
||||
}
|
||||
defer addResponse.Body.Close()
|
||||
|
||||
prog.N++
|
||||
|
||||
stage.Current = ""
|
||||
|
||||
@@ -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 = "3.0.1"
|
||||
JSONSchemaVersion = "3.2.1"
|
||||
)
|
||||
|
||||
@@ -47,8 +47,10 @@ func hasMetadata(p pkg.Package) bool {
|
||||
|
||||
func decodeComponent(c *cyclonedx.Component) *pkg.Package {
|
||||
values := map[string]string{}
|
||||
for _, p := range *c.Properties {
|
||||
values[p.Name] = p.Value
|
||||
if c.Properties != nil {
|
||||
for _, p := range *c.Properties {
|
||||
values[p.Name] = p.Value
|
||||
}
|
||||
}
|
||||
|
||||
p := &pkg.Package{
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/CycloneDX/cyclonedx-go"
|
||||
|
||||
"github.com/anchore/syft/internal/formats/common"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -44,7 +46,7 @@ func GetDecoder(format cyclonedx.BOMFileFormat) sbom.Decoder {
|
||||
|
||||
func toSyftModel(bom *cyclonedx.BOM) (*sbom.SBOM, error) {
|
||||
meta := source.Metadata{}
|
||||
if bom.Metadata != nil {
|
||||
if bom.Metadata != nil && bom.Metadata.Component != nil {
|
||||
meta = decodeMetadata(bom.Metadata.Component)
|
||||
}
|
||||
s := &sbom.SBOM{
|
||||
@@ -157,6 +159,14 @@ func linuxReleaseFromOSComponent(component *cyclonedx.Component) *linux.Release
|
||||
}
|
||||
}
|
||||
|
||||
if component.Properties != nil {
|
||||
values := map[string]string{}
|
||||
for _, p := range *component.Properties {
|
||||
values[p.Name] = p.Value
|
||||
}
|
||||
common.DecodeInto(&rel, values, "syft:distro", CycloneDXFields)
|
||||
}
|
||||
|
||||
return rel
|
||||
}
|
||||
|
||||
|
||||
@@ -258,3 +258,28 @@ func Test_decode(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_missingDataDecode(t *testing.T) {
|
||||
bom := &cyclonedx.BOM{
|
||||
Metadata: nil,
|
||||
Components: &[]cyclonedx.Component{},
|
||||
}
|
||||
|
||||
_, err := toSyftModel(bom)
|
||||
assert.NoError(t, err)
|
||||
|
||||
bom.Metadata = &cyclonedx.Metadata{}
|
||||
|
||||
_, err = toSyftModel(bom)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pkg := decodeComponent(&cyclonedx.Component{
|
||||
Licenses: &cyclonedx.Licenses{
|
||||
{
|
||||
License: nil,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
assert.Len(t, pkg.Licenses, 0)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ func encodeLicenses(p pkg.Package) *cyclonedx.Licenses {
|
||||
func decodeLicenses(c *cyclonedx.Component) (out []string) {
|
||||
if c.Licenses != nil {
|
||||
for _, l := range *c.Licenses {
|
||||
out = append(out, l.License.ID)
|
||||
if l.License != nil {
|
||||
out = append(out, l.License.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mholt/archiver/v3"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
// toGithubModel converts the provided SBOM to a GitHub dependency model
|
||||
func toGithubModel(s *sbom.SBOM) DependencySnapshot {
|
||||
scanTime := time.Now().Format(time.RFC3339) // TODO is there a record of this somewhere?
|
||||
v := version.FromBuild().Version
|
||||
if v == "[not provided]" {
|
||||
v = "0.0.0-dev"
|
||||
}
|
||||
return DependencySnapshot{
|
||||
Version: 0,
|
||||
// TODO allow property input to specify the Job, Sha, and Ref
|
||||
Detector: DetectorMetadata{
|
||||
Name: internal.ApplicationName,
|
||||
URL: "https://github.com/anchore/syft",
|
||||
Version: v,
|
||||
},
|
||||
Metadata: toSnapshotMetadata(s),
|
||||
Manifests: toGithubManifests(s),
|
||||
Scanned: scanTime,
|
||||
}
|
||||
}
|
||||
|
||||
// toSnapshotMetadata captures the linux distribution information and other metadata
|
||||
func toSnapshotMetadata(s *sbom.SBOM) Metadata {
|
||||
out := Metadata{}
|
||||
|
||||
if s.Artifacts.LinuxDistribution != nil {
|
||||
d := s.Artifacts.LinuxDistribution
|
||||
qualifiers := packageurl.Qualifiers{}
|
||||
if len(d.IDLike) > 0 {
|
||||
qualifiers = append(qualifiers, packageurl.Qualifier{
|
||||
Key: "like",
|
||||
Value: strings.Join(d.IDLike, ","),
|
||||
})
|
||||
}
|
||||
purl := packageurl.NewPackageURL("generic", "", d.ID, d.VersionID, qualifiers, "")
|
||||
out["syft:distro"] = purl.ToString()
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func filesystem(p pkg.Package) string {
|
||||
if len(p.Locations) > 0 {
|
||||
return p.Locations[0].FileSystemID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// isArchive returns true if the path appears to be an archive
|
||||
func isArchive(path string) bool {
|
||||
_, err := archiver.ByExtension(path)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// toPath Generates a string representation of the package location, optionally including the layer hash
|
||||
func toPath(s source.Metadata, p pkg.Package) string {
|
||||
inputPath := strings.TrimPrefix(s.Path, "./")
|
||||
if inputPath == "." {
|
||||
inputPath = ""
|
||||
}
|
||||
if len(p.Locations) > 0 {
|
||||
location := p.Locations[0]
|
||||
packagePath := location.RealPath
|
||||
if location.VirtualPath != "" {
|
||||
packagePath = location.VirtualPath
|
||||
}
|
||||
packagePath = strings.TrimPrefix(packagePath, "/")
|
||||
switch s.Scheme {
|
||||
case source.ImageScheme:
|
||||
image := strings.ReplaceAll(s.ImageMetadata.UserInput, ":/", "//")
|
||||
return fmt.Sprintf("%s:/%s", image, packagePath)
|
||||
case source.FileScheme:
|
||||
if isArchive(inputPath) {
|
||||
return fmt.Sprintf("%s:/%s", inputPath, packagePath)
|
||||
}
|
||||
return inputPath
|
||||
case source.DirectoryScheme:
|
||||
if inputPath != "" {
|
||||
return fmt.Sprintf("%s/%s", inputPath, packagePath)
|
||||
}
|
||||
return packagePath
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%s%s", inputPath, s.ImageMetadata.UserInput)
|
||||
}
|
||||
|
||||
// toGithubManifests manifests, each of which represents a specific location that has dependencies
|
||||
func toGithubManifests(s *sbom.SBOM) Manifests {
|
||||
manifests := map[string]*Manifest{}
|
||||
|
||||
for _, p := range s.Artifacts.PackageCatalog.Sorted() {
|
||||
path := toPath(s.Source, p)
|
||||
manifest, ok := manifests[path]
|
||||
if !ok {
|
||||
manifest = &Manifest{
|
||||
Name: path,
|
||||
File: FileInfo{
|
||||
SourceLocation: path,
|
||||
},
|
||||
Resolved: DependencyGraph{},
|
||||
}
|
||||
fs := filesystem(p)
|
||||
if fs != "" {
|
||||
manifest.Metadata = Metadata{
|
||||
"syft:filesystem": fs,
|
||||
}
|
||||
}
|
||||
manifests[path] = manifest
|
||||
}
|
||||
|
||||
name := dependencyName(p)
|
||||
manifest.Resolved[name] = DependencyNode{
|
||||
Purl: p.PURL,
|
||||
Metadata: toDependencyMetadata(p),
|
||||
Relationship: toDependencyRelationshipType(p),
|
||||
Scope: toDependencyScope(p),
|
||||
Dependencies: toDependencies(s, p),
|
||||
}
|
||||
}
|
||||
|
||||
out := Manifests{}
|
||||
for k, v := range manifests {
|
||||
out[k] = *v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// dependencyName to make things a little nicer to read; this might end up being lossy
|
||||
func dependencyName(p pkg.Package) string {
|
||||
purl, err := packageurl.FromString(p.PURL)
|
||||
if err != nil {
|
||||
log.Warnf("Invalid PURL for package: '%s' PURL: '%s' (%w)", p.Name, p.PURL, err)
|
||||
return ""
|
||||
}
|
||||
// don't use qualifiers for this
|
||||
purl.Qualifiers = nil
|
||||
return purl.ToString()
|
||||
}
|
||||
|
||||
func toDependencyScope(_ pkg.Package) DependencyScope {
|
||||
return DependencyScopeRuntime
|
||||
}
|
||||
|
||||
func toDependencyRelationshipType(_ pkg.Package) DependencyRelationship {
|
||||
return DependencyRelationshipDirect
|
||||
}
|
||||
|
||||
func toDependencyMetadata(_ pkg.Package) Metadata {
|
||||
// We have limited properties: up to 8 with reasonably small values
|
||||
// For now, we are encoding the location as part of the key, we are encoding PURLs with most
|
||||
// of the other information Grype might need; and the distro information at the top level
|
||||
// so we don't need anything here yet
|
||||
return Metadata{}
|
||||
}
|
||||
|
||||
func toDependencies(s *sbom.SBOM, p pkg.Package) (out []string) {
|
||||
for _, r := range s.Relationships {
|
||||
if r.From.ID() == p.ID() {
|
||||
if p, ok := r.To.(pkg.Package); ok {
|
||||
out = append(out, dependencyName(p))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func Test_toGithubModel(t *testing.T) {
|
||||
s := sbom.SBOM{
|
||||
Source: source.Metadata{
|
||||
Scheme: source.ImageScheme,
|
||||
ImageMetadata: source.ImageMetadata{
|
||||
UserInput: "ubuntu:18.04",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
},
|
||||
Artifacts: sbom.Artifacts{
|
||||
LinuxDistribution: &linux.Release{
|
||||
ID: "ubuntu",
|
||||
VersionID: "18.04",
|
||||
IDLike: []string{"debian"},
|
||||
},
|
||||
PackageCatalog: pkg.NewCatalog(),
|
||||
},
|
||||
}
|
||||
for _, p := range []pkg.Package{
|
||||
{
|
||||
Name: "pkg-1",
|
||||
Version: "1.0.1",
|
||||
Locations: []source.Location{{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/usr/lib",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
Name: "pkg-2",
|
||||
Version: "2.0.2",
|
||||
Locations: []source.Location{{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/usr/lib",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
Name: "pkg-3",
|
||||
Version: "3.0.3",
|
||||
Locations: []source.Location{{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/etc",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
}},
|
||||
},
|
||||
} {
|
||||
p.PURL = packageurl.NewPackageURL(
|
||||
"generic",
|
||||
"",
|
||||
p.Name,
|
||||
p.Version,
|
||||
nil,
|
||||
"",
|
||||
).ToString()
|
||||
s.Artifacts.PackageCatalog.Add(p)
|
||||
}
|
||||
|
||||
actual := toGithubModel(&s)
|
||||
|
||||
expected := DependencySnapshot{
|
||||
Version: 0,
|
||||
Detector: DetectorMetadata{
|
||||
Name: "syft",
|
||||
Version: "0.0.0-dev",
|
||||
URL: "https://github.com/anchore/syft",
|
||||
},
|
||||
Metadata: Metadata{
|
||||
"syft:distro": "pkg:generic/ubuntu@18.04?like=debian",
|
||||
},
|
||||
Scanned: actual.Scanned,
|
||||
Manifests: Manifests{
|
||||
"ubuntu:18.04:/usr/lib": Manifest{
|
||||
Name: "ubuntu:18.04:/usr/lib",
|
||||
File: FileInfo{
|
||||
SourceLocation: "ubuntu:18.04:/usr/lib",
|
||||
},
|
||||
Metadata: Metadata{
|
||||
"syft:filesystem": "fsid-1",
|
||||
},
|
||||
Resolved: DependencyGraph{
|
||||
"pkg:generic/pkg-1@1.0.1": DependencyNode{
|
||||
Purl: "pkg:generic/pkg-1@1.0.1",
|
||||
Scope: DependencyScopeRuntime,
|
||||
Relationship: DependencyRelationshipDirect,
|
||||
},
|
||||
"pkg:generic/pkg-2@2.0.2": DependencyNode{
|
||||
Purl: "pkg:generic/pkg-2@2.0.2",
|
||||
Scope: DependencyScopeRuntime,
|
||||
Relationship: DependencyRelationshipDirect,
|
||||
},
|
||||
},
|
||||
},
|
||||
"ubuntu:18.04:/etc": Manifest{
|
||||
Name: "ubuntu:18.04:/etc",
|
||||
File: FileInfo{
|
||||
SourceLocation: "ubuntu:18.04:/etc",
|
||||
},
|
||||
Metadata: Metadata{
|
||||
"syft:filesystem": "fsid-1",
|
||||
},
|
||||
Resolved: DependencyGraph{
|
||||
"pkg:generic/pkg-3@3.0.3": DependencyNode{
|
||||
Purl: "pkg:generic/pkg-3@3.0.3",
|
||||
Scope: DependencyScopeRuntime,
|
||||
Relationship: DependencyRelationshipDirect,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// just using JSONEq because it gives a comprehensible diff
|
||||
s1, _ := json.Marshal(expected)
|
||||
s2, _ := json.Marshal(actual)
|
||||
assert.JSONEq(t, string(s1), string(s2))
|
||||
|
||||
// Just test the other schemes:
|
||||
s.Source.Path = "."
|
||||
s.Source.Scheme = source.DirectoryScheme
|
||||
actual = toGithubModel(&s)
|
||||
assert.Equal(t, "etc", actual.Manifests["etc"].Name)
|
||||
|
||||
s.Source.Path = "./artifacts"
|
||||
s.Source.Scheme = source.DirectoryScheme
|
||||
actual = toGithubModel(&s)
|
||||
assert.Equal(t, "artifacts/etc", actual.Manifests["artifacts/etc"].Name)
|
||||
|
||||
s.Source.Path = "/artifacts"
|
||||
s.Source.Scheme = source.DirectoryScheme
|
||||
actual = toGithubModel(&s)
|
||||
assert.Equal(t, "/artifacts/etc", actual.Manifests["/artifacts/etc"].Name)
|
||||
|
||||
s.Source.Path = "./executable"
|
||||
s.Source.Scheme = source.FileScheme
|
||||
actual = toGithubModel(&s)
|
||||
assert.Equal(t, "executable", actual.Manifests["executable"].Name)
|
||||
|
||||
s.Source.Path = "./archive.tar.gz"
|
||||
s.Source.Scheme = source.FileScheme
|
||||
actual = toGithubModel(&s)
|
||||
assert.Equal(t, "archive.tar.gz:/etc", actual.Manifests["archive.tar.gz:/etc"].Name)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
const ID sbom.FormatID = "github-0-json"
|
||||
|
||||
func Format() sbom.Format {
|
||||
return sbom.NewFormat(
|
||||
ID,
|
||||
func(writer io.Writer, sbom sbom.SBOM) error {
|
||||
bom := toGithubModel(&sbom)
|
||||
|
||||
bytes, err := json.MarshalIndent(bom, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = writer.Write(bytes)
|
||||
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package github
|
||||
|
||||
// Derived from: https://gist.github.com/reiddraper/fdab2883db0f372c146d1a750fc1c43f
|
||||
|
||||
type DependencySnapshot struct {
|
||||
Version int `json:"version"`
|
||||
Job Job `json:"job,omitempty"` // !omitempty
|
||||
Sha string `json:"sha,omitempty"` // !omitempty sha of the Git commit
|
||||
Ref string `json:"ref,omitempty"` // !omitempty ref of the Git commit example "refs/heads/main"
|
||||
Detector DetectorMetadata `json:"detector,omitempty"`
|
||||
Metadata Metadata `json:"metadata,omitempty"`
|
||||
Manifests Manifests `json:"manifests,omitempty"`
|
||||
Scanned ISO8601Date `json:"scanned,omitempty"`
|
||||
}
|
||||
|
||||
type Job struct {
|
||||
Name string `json:"name,omitempty"` // !omitempty
|
||||
ID string `json:"id,omitempty"` // !omitempty
|
||||
HTMLURL string `json:"html_url,omitempty"`
|
||||
}
|
||||
|
||||
type DetectorMetadata struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
type Manifests map[string]Manifest
|
||||
|
||||
// Manifest A collection of related dependencies, either declared in a file,
|
||||
// or representing a logical group of dependencies.
|
||||
type Manifest struct {
|
||||
Name string `json:"name"`
|
||||
File FileInfo `json:"file"`
|
||||
Metadata Metadata `json:"metadata,omitempty"`
|
||||
Resolved DependencyGraph `json:"resolved,omitempty"`
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
SourceLocation string `json:"source_location,omitempty"`
|
||||
}
|
||||
|
||||
// DependencyRelationship A notation of whether a dependency is requested directly
|
||||
// by this manifest, or is a dependency of another dependency.
|
||||
type DependencyRelationship string
|
||||
|
||||
const (
|
||||
DependencyRelationshipDirect DependencyRelationship = "direct"
|
||||
DependencyRelationshipIndirect DependencyRelationship = "indirect"
|
||||
)
|
||||
|
||||
// DependencyScope A notation of whether the dependency is required for the primary
|
||||
// build artifact (runtime), or is only used for development.
|
||||
// Future versions of this specification may allow for more granular
|
||||
// scopes, like `runtimeserver`, `runtimeshipped`,
|
||||
// `developmenttest`, `developmentbenchmark`.
|
||||
type DependencyScope string
|
||||
|
||||
const (
|
||||
DependencyScopeRuntime DependencyScope = "runtime"
|
||||
DependencyScopeDevelopment DependencyScope = "development"
|
||||
)
|
||||
|
||||
type DependencyNode struct {
|
||||
Purl string `json:"purl,omitempty"`
|
||||
Metadata Metadata `json:"metadata,omitempty"`
|
||||
Relationship DependencyRelationship `json:"relationship,omitempty"`
|
||||
Scope DependencyScope `json:"scope,omitempty"`
|
||||
Dependencies []string `json:"dependencies,omitempty"`
|
||||
}
|
||||
|
||||
type DependencyGraph map[string]DependencyNode
|
||||
|
||||
type ISO8601Date = string
|
||||
|
||||
type Scalar interface{} // should be: null | boolean | string | number
|
||||
|
||||
type Metadata map[string]Scalar
|
||||
@@ -124,6 +124,12 @@ func (p *Package) UnmarshalJSON(b []byte) error {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.GolangBinMetadataType:
|
||||
var payload pkg.GolangBinMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
default:
|
||||
log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUnmarshalPackageGolang(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
p *Package
|
||||
packageData []byte
|
||||
}{
|
||||
{
|
||||
name: "Package.UnmarshalJSON unmarshals PackageBasicData",
|
||||
p: &Package{},
|
||||
packageData: []byte(`{
|
||||
"id": "8b594519bc23da50",
|
||||
"name": "gopkg.in/square/go-jose.v2",
|
||||
"version": "v2.6.0",
|
||||
"type": "go-module",
|
||||
"foundBy": "go-module-binary-cataloger",
|
||||
"locations": [
|
||||
{
|
||||
"path": "/Users/hal/go/bin/syft"
|
||||
}
|
||||
],
|
||||
"licenses": [],
|
||||
"language": "go",
|
||||
"cpes": [],
|
||||
"purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0",
|
||||
"metadataType": "GolangBinMetadata",
|
||||
"metadata": {
|
||||
"goCompiledVersion": "go1.18",
|
||||
"architecture": "amd64",
|
||||
"h1Digest": "h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI="
|
||||
}
|
||||
}`),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := test.p.UnmarshalJSON(test.packageData)
|
||||
if err != nil {
|
||||
t.Fatalf("could not unmarshal packageData: %v", err)
|
||||
}
|
||||
|
||||
assert.NotNil(t, test.p.Metadata)
|
||||
golangMetadata := test.p.Metadata.(pkg.GolangBinMetadata)
|
||||
assert.NotEmpty(t, golangMetadata)
|
||||
assert.Equal(t, "go1.18", golangMetadata.GoCompiledVersion)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.0.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.0.1.json"
|
||||
"version": "3.2.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.2.1.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.0.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.0.1.json"
|
||||
"version": "3.2.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.2.1.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.0.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.0.1.json"
|
||||
"version": "3.2.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.2.1.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
)
|
||||
|
||||
func toSyftModel(doc model.Document) (*sbom.SBOM, error) {
|
||||
catalog := toSyftCatalog(doc.Artifacts)
|
||||
idAliases := make(map[string]string)
|
||||
|
||||
catalog := toSyftCatalog(doc.Artifacts, idAliases)
|
||||
|
||||
return &sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
@@ -21,7 +23,7 @@ func toSyftModel(doc model.Document) (*sbom.SBOM, error) {
|
||||
},
|
||||
Source: *toSyftSourceData(doc.Source),
|
||||
Descriptor: toSyftDescriptor(doc.Descriptor),
|
||||
Relationships: toSyftRelationships(&doc, catalog, doc.ArtifactRelationships),
|
||||
Relationships: toSyftRelationships(&doc, catalog, doc.ArtifactRelationships, idAliases),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -46,7 +48,7 @@ func toSyftLinuxRelease(d model.LinuxRelease) *linux.Release {
|
||||
}
|
||||
}
|
||||
|
||||
func toSyftRelationships(doc *model.Document, catalog *pkg.Catalog, relationships []model.Relationship) []artifact.Relationship {
|
||||
func toSyftRelationships(doc *model.Document, catalog *pkg.Catalog, relationships []model.Relationship, idAliases map[string]string) []artifact.Relationship {
|
||||
idMap := make(map[string]interface{})
|
||||
|
||||
for _, p := range catalog.Sorted() {
|
||||
@@ -62,7 +64,7 @@ func toSyftRelationships(doc *model.Document, catalog *pkg.Catalog, relationship
|
||||
|
||||
var out []artifact.Relationship
|
||||
for _, r := range relationships {
|
||||
syftRelationship := toSyftRelationship(idMap, r)
|
||||
syftRelationship := toSyftRelationship(idMap, r, idAliases)
|
||||
if syftRelationship != nil {
|
||||
out = append(out, *syftRelationship)
|
||||
}
|
||||
@@ -70,13 +72,20 @@ func toSyftRelationships(doc *model.Document, catalog *pkg.Catalog, relationship
|
||||
return out
|
||||
}
|
||||
|
||||
func toSyftRelationship(idMap map[string]interface{}, relationship model.Relationship) *artifact.Relationship {
|
||||
from, ok := idMap[relationship.Parent].(artifact.Identifiable)
|
||||
func toSyftRelationship(idMap map[string]interface{}, relationship model.Relationship, idAliases map[string]string) *artifact.Relationship {
|
||||
id := func(id string) string {
|
||||
aliased, ok := idAliases[id]
|
||||
if ok {
|
||||
return aliased
|
||||
}
|
||||
return id
|
||||
}
|
||||
from, ok := idMap[id(relationship.Parent)].(artifact.Identifiable)
|
||||
if !ok {
|
||||
log.Warnf("relationship mapping from key %s is not a valid artifact.Identifiable type: %+v", relationship.Parent, idMap[relationship.Parent])
|
||||
return nil
|
||||
}
|
||||
to, ok := idMap[relationship.Child].(artifact.Identifiable)
|
||||
to, ok := idMap[id(relationship.Child)].(artifact.Identifiable)
|
||||
if !ok {
|
||||
log.Warnf("relationship mapping to key %s is not a valid artifact.Identifiable type: %+v", relationship.Child, idMap[relationship.Child])
|
||||
return nil
|
||||
@@ -128,15 +137,15 @@ func toSyftSourceData(s model.Source) *source.Metadata {
|
||||
return nil
|
||||
}
|
||||
|
||||
func toSyftCatalog(pkgs []model.Package) *pkg.Catalog {
|
||||
func toSyftCatalog(pkgs []model.Package, idAliases map[string]string) *pkg.Catalog {
|
||||
catalog := pkg.NewCatalog()
|
||||
for _, p := range pkgs {
|
||||
catalog.Add(toSyftPackage(p))
|
||||
catalog.Add(toSyftPackage(p, idAliases))
|
||||
}
|
||||
return catalog
|
||||
}
|
||||
|
||||
func toSyftPackage(p model.Package) pkg.Package {
|
||||
func toSyftPackage(p model.Package, idAliases map[string]string) pkg.Package {
|
||||
var cpes []pkg.CPE
|
||||
for _, c := range p.CPEs {
|
||||
value, err := pkg.NewCPE(c)
|
||||
@@ -153,7 +162,7 @@ func toSyftPackage(p model.Package) pkg.Package {
|
||||
locations[i] = source.NewLocationFromCoordinates(c)
|
||||
}
|
||||
|
||||
return pkg.Package{
|
||||
out := pkg.Package{
|
||||
Name: p.Name,
|
||||
Version: p.Version,
|
||||
FoundBy: p.FoundBy,
|
||||
@@ -166,4 +175,13 @@ func toSyftPackage(p model.Package) pkg.Package {
|
||||
MetadataType: p.MetadataType,
|
||||
Metadata: p.Metadata,
|
||||
}
|
||||
|
||||
out.SetID()
|
||||
|
||||
id := string(out.ID())
|
||||
if id != p.ID {
|
||||
idAliases[p.ID] = id
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/internal/formats/syftjson/model"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -79,3 +80,46 @@ func Test_toSyftSourceData(t *testing.T) {
|
||||
// assert all possible schemes were under test
|
||||
assert.ElementsMatch(t, allSchemes.List(), testedSchemes.List(), "not all source.Schemes are under test")
|
||||
}
|
||||
|
||||
func Test_idsHaveChanged(t *testing.T) {
|
||||
s, err := toSyftModel(model.Document{
|
||||
Source: model.Source{
|
||||
Type: "file",
|
||||
Target: "some/path",
|
||||
},
|
||||
Artifacts: []model.Package{
|
||||
{
|
||||
PackageBasicData: model.PackageBasicData{
|
||||
ID: "1",
|
||||
Name: "pkg-1",
|
||||
},
|
||||
},
|
||||
{
|
||||
PackageBasicData: model.PackageBasicData{
|
||||
ID: "2",
|
||||
Name: "pkg-2",
|
||||
},
|
||||
},
|
||||
},
|
||||
ArtifactRelationships: []model.Relationship{
|
||||
{
|
||||
Parent: "1",
|
||||
Child: "2",
|
||||
Type: string(artifact.ContainsRelationship),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, s.Relationships, 1)
|
||||
|
||||
r := s.Relationships[0]
|
||||
|
||||
from := s.Artifacts.PackageCatalog.Package(r.From.ID())
|
||||
assert.NotNil(t, from)
|
||||
assert.Equal(t, "pkg-1", from.Name)
|
||||
|
||||
to := s.Artifacts.PackageCatalog.Package(r.To.ID())
|
||||
assert.NotNil(t, to)
|
||||
assert.Equal(t, "pkg-2", to.Name)
|
||||
}
|
||||
|
||||
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
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/anchore/syft/internal/formats/cyclonedxjson"
|
||||
"github.com/anchore/syft/internal/formats/cyclonedxxml"
|
||||
"github.com/anchore/syft/internal/formats/github"
|
||||
"github.com/anchore/syft/internal/formats/spdx22json"
|
||||
"github.com/anchore/syft/internal/formats/spdx22tagvalue"
|
||||
"github.com/anchore/syft/internal/formats/syftjson"
|
||||
@@ -21,6 +22,7 @@ const (
|
||||
TableFormatID = table.ID
|
||||
CycloneDxXMLFormatID = cyclonedxxml.ID
|
||||
CycloneDxJSONFormatID = cyclonedxjson.ID
|
||||
GitHubID = github.ID
|
||||
SPDXTagValueFormatID = spdx22tagvalue.ID
|
||||
SPDXJSONFormatID = spdx22json.ID
|
||||
)
|
||||
@@ -32,6 +34,7 @@ func init() {
|
||||
syftjson.Format(),
|
||||
cyclonedxxml.Format(),
|
||||
cyclonedxjson.Format(),
|
||||
github.Format(),
|
||||
spdx22tagvalue.Format(),
|
||||
spdx22json.Format(),
|
||||
table.Format(),
|
||||
@@ -71,6 +74,8 @@ func FormatByName(name string) sbom.Format {
|
||||
return FormatByID(cyclonedxxml.ID)
|
||||
case "cyclonedxjson":
|
||||
return FormatByID(cyclonedxjson.ID)
|
||||
case "github":
|
||||
return FormatByID(github.ID)
|
||||
case "spdx", "spdxtv", "spdxtagvalue":
|
||||
return FormatByID(spdx22tagvalue.ID)
|
||||
case "spdxjson":
|
||||
|
||||
@@ -17,6 +17,7 @@ var (
|
||||
"org",
|
||||
"net",
|
||||
"io",
|
||||
"be",
|
||||
}
|
||||
|
||||
primaryJavaManifestGroupIDFields = []string{
|
||||
|
||||
@@ -4,10 +4,12 @@ Package golang provides a concrete Cataloger implementation for go.mod files.
|
||||
package golang
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -38,19 +40,51 @@ func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []arti
|
||||
}
|
||||
|
||||
for _, location := range fileMatches {
|
||||
r, err := resolver.FileContentsByLocation(location)
|
||||
readerCloser, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
return pkgs, nil, fmt.Errorf("failed to resolve file contents by location=%q: %w", location.RealPath, err)
|
||||
log.Warnf("golang cataloger: opening file: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
goPkgs, err := parseGoBin(location, r, openExe)
|
||||
reader, err := getUnionReader(readerCloser)
|
||||
if err != nil {
|
||||
log.Warnf("could not parse possible go binary at %q: %+v", location.RealPath, err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
internal.CloseAndLogError(r, location.RealPath)
|
||||
pkgs = append(pkgs, goPkgs...)
|
||||
mods, archs := scanFile(reader, location.RealPath)
|
||||
internal.CloseAndLogError(readerCloser, location.RealPath)
|
||||
|
||||
for i, mod := range mods {
|
||||
pkgs = append(pkgs, buildGoPkgInfo(location, mod, archs[i])...)
|
||||
}
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
func getUnionReader(readerCloser io.ReadCloser) (unionReader, error) {
|
||||
reader, ok := readerCloser.(unionReader)
|
||||
if ok {
|
||||
return reader, nil
|
||||
}
|
||||
log.Debugf("golang cataloger: unable to use stereoscope file, reading entire contents")
|
||||
|
||||
b, err := ioutil.ReadAll(readerCloser)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read contents from go binary: %w", err)
|
||||
}
|
||||
|
||||
bytesReader := bytes.NewReader(b)
|
||||
|
||||
reader = struct {
|
||||
io.ReadCloser
|
||||
io.ReaderAt
|
||||
io.Seeker
|
||||
}{
|
||||
ReadCloser: io.NopCloser(bytesReader),
|
||||
ReaderAt: bytesReader,
|
||||
Seeker: bytesReader,
|
||||
}
|
||||
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_getUnionReader_notUnionReader(t *testing.T) {
|
||||
expectedContents := "this is a test"
|
||||
reader := io.NopCloser(strings.NewReader(expectedContents))
|
||||
|
||||
// make certain that the test fixture does not implement the union reader
|
||||
_, ok := reader.(unionReader)
|
||||
require.False(t, ok)
|
||||
|
||||
actual, err := getUnionReader(reader)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, ok = actual.(unionReader)
|
||||
require.True(t, ok)
|
||||
|
||||
b, err := io.ReadAll(actual)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, expectedContents, string(b))
|
||||
}
|
||||
@@ -1,354 +0,0 @@
|
||||
// This code was copied from the Go std library.
|
||||
// https://github.com/golang/go/blob/master/src/cmd/go/internal/version/exe.go
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//nolint
|
||||
package golang
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// An exe is a generic interface to an OS executable (ELF, Mach-O, PE, XCOFF).
|
||||
type exe interface {
|
||||
// Close closes the underlying file.
|
||||
Close() error
|
||||
|
||||
// ReadData reads and returns up to size byte starting at virtual address addr.
|
||||
ReadData(addr, size uint64) ([]byte, error)
|
||||
|
||||
// ArchName returns a string that represents the CPU architecture of the executable.
|
||||
ArchName() string
|
||||
|
||||
// DataStart returns the writable data segment start address.
|
||||
DataStart() uint64
|
||||
}
|
||||
|
||||
// openExe opens file and returns it as an exe.
|
||||
// we changed this signature from accpeting a string
|
||||
// to a ReadCloser so we could adapt the code to the
|
||||
// stereoscope api. We removed the file open methods.
|
||||
func openExe(file io.ReadCloser) ([]exe, error) {
|
||||
/*
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := make([]byte, 16)
|
||||
if _, err := io.ReadFull(f, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Seek(0, 0)
|
||||
*/
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := bytes.NewReader(data)
|
||||
f := io.NewSectionReader(r, 0, int64(len(data)))
|
||||
if bytes.HasPrefix(data, []byte("\x7FELF")) {
|
||||
e, err := elf.NewFile(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []exe{&elfExe{file, e}}, nil
|
||||
}
|
||||
|
||||
if bytes.HasPrefix(data, []byte("MZ")) {
|
||||
e, err := pe.NewFile(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []exe{&peExe{file, e}}, nil
|
||||
}
|
||||
|
||||
if bytes.HasPrefix(data, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(data[1:], []byte("\xFA\xED\xFE")) {
|
||||
e, err := macho.NewFile(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []exe{&machoExe{file, e}}, nil
|
||||
}
|
||||
|
||||
// adding macho multi-architecture support (both for 64bit and 32 bit)... this case is not in the stdlib yet
|
||||
if bytes.HasPrefix(data, []byte("\xCA\xFE\xBA\xBE")) || bytes.HasPrefix(data, []byte("\xCA\xFE\xBA\xBF")) {
|
||||
fatExe, err := macho.NewFatFile(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var exes []exe
|
||||
for _, arch := range fatExe.Arches {
|
||||
exes = append(exes, &machoExe{file, arch.File})
|
||||
}
|
||||
return exes, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unrecognized executable format")
|
||||
}
|
||||
|
||||
// elfExe is the ELF implementation of the exe interface.
|
||||
// updated os to be io.ReadCloser to interopt with stereoscope
|
||||
type elfExe struct {
|
||||
os io.ReadCloser
|
||||
f *elf.File
|
||||
}
|
||||
|
||||
func (x *elfExe) Close() error {
|
||||
return x.os.Close()
|
||||
}
|
||||
|
||||
func (x *elfExe) ArchName() string {
|
||||
return cleanElfArch(x.f.Machine)
|
||||
}
|
||||
|
||||
func cleanElfArch(machine elf.Machine) string {
|
||||
return strings.TrimPrefix(strings.ToLower(machine.String()), "em_")
|
||||
}
|
||||
|
||||
func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) {
|
||||
for _, prog := range x.f.Progs {
|
||||
if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 {
|
||||
n := prog.Vaddr + prog.Filesz - addr
|
||||
if n > size {
|
||||
n = size
|
||||
}
|
||||
data := make([]byte, n)
|
||||
_, err := prog.ReadAt(data, int64(addr-prog.Vaddr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("address not mapped")
|
||||
}
|
||||
|
||||
func (x *elfExe) DataStart() uint64 {
|
||||
for _, s := range x.f.Sections {
|
||||
if s.Name == ".go.buildinfo" {
|
||||
return s.Addr
|
||||
}
|
||||
}
|
||||
for _, p := range x.f.Progs {
|
||||
if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_X|elf.PF_W) == elf.PF_W {
|
||||
return p.Vaddr
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// peExe is the PE (Windows Portable Executable) implementation of the exe interface.
|
||||
type peExe struct {
|
||||
os io.ReadCloser
|
||||
f *pe.File
|
||||
}
|
||||
|
||||
func (x *peExe) Close() error {
|
||||
return x.os.Close()
|
||||
}
|
||||
|
||||
func (x *peExe) ArchName() string {
|
||||
// from: debug/pe/pe.go
|
||||
switch x.f.Machine {
|
||||
case pe.IMAGE_FILE_MACHINE_AM33:
|
||||
return "amd33"
|
||||
case pe.IMAGE_FILE_MACHINE_AMD64:
|
||||
return "amd64"
|
||||
case pe.IMAGE_FILE_MACHINE_ARM:
|
||||
return "arm"
|
||||
case pe.IMAGE_FILE_MACHINE_ARMNT:
|
||||
return "armnt"
|
||||
case pe.IMAGE_FILE_MACHINE_ARM64:
|
||||
return "arm64"
|
||||
case pe.IMAGE_FILE_MACHINE_EBC:
|
||||
return "ebc"
|
||||
case pe.IMAGE_FILE_MACHINE_I386:
|
||||
return "i386"
|
||||
case pe.IMAGE_FILE_MACHINE_IA64:
|
||||
return "ia64"
|
||||
case pe.IMAGE_FILE_MACHINE_M32R:
|
||||
return "m32r"
|
||||
case pe.IMAGE_FILE_MACHINE_MIPS16:
|
||||
return "mips16"
|
||||
case pe.IMAGE_FILE_MACHINE_MIPSFPU:
|
||||
return "mipsfpu"
|
||||
case pe.IMAGE_FILE_MACHINE_MIPSFPU16:
|
||||
return "mipsfpu16"
|
||||
case pe.IMAGE_FILE_MACHINE_POWERPC:
|
||||
return "ppc"
|
||||
case pe.IMAGE_FILE_MACHINE_POWERPCFP:
|
||||
return "ppcfp"
|
||||
case pe.IMAGE_FILE_MACHINE_R4000:
|
||||
return "r4000"
|
||||
case pe.IMAGE_FILE_MACHINE_SH3:
|
||||
return "sh3"
|
||||
case pe.IMAGE_FILE_MACHINE_SH3DSP:
|
||||
return "sh3dsp"
|
||||
case pe.IMAGE_FILE_MACHINE_SH4:
|
||||
return "sh4"
|
||||
case pe.IMAGE_FILE_MACHINE_SH5:
|
||||
return "sh5"
|
||||
case pe.IMAGE_FILE_MACHINE_THUMB:
|
||||
return "thumb"
|
||||
case pe.IMAGE_FILE_MACHINE_WCEMIPSV2:
|
||||
return "wcemipsv2"
|
||||
default:
|
||||
return fmt.Sprintf("unknown-pe-machine-%d", x.f.Machine)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *peExe) imageBase() uint64 {
|
||||
switch oh := x.f.OptionalHeader.(type) {
|
||||
case *pe.OptionalHeader32:
|
||||
return uint64(oh.ImageBase)
|
||||
case *pe.OptionalHeader64:
|
||||
return oh.ImageBase
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *peExe) ReadData(addr, size uint64) ([]byte, error) {
|
||||
addr -= x.imageBase()
|
||||
for _, sect := range x.f.Sections {
|
||||
if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) {
|
||||
n := uint64(sect.VirtualAddress+sect.Size) - addr
|
||||
if n > size {
|
||||
n = size
|
||||
}
|
||||
data := make([]byte, n)
|
||||
_, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("address not mapped")
|
||||
}
|
||||
|
||||
func (x *peExe) DataStart() uint64 {
|
||||
// Assume data is first writable section.
|
||||
const (
|
||||
IMAGE_SCN_CNT_CODE = 0x00000020
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
|
||||
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
|
||||
IMAGE_SCN_MEM_EXECUTE = 0x20000000
|
||||
IMAGE_SCN_MEM_READ = 0x40000000
|
||||
IMAGE_SCN_MEM_WRITE = 0x80000000
|
||||
IMAGE_SCN_MEM_DISCARDABLE = 0x2000000
|
||||
IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000
|
||||
IMAGE_SCN_ALIGN_32BYTES = 0x600000
|
||||
)
|
||||
for _, sect := range x.f.Sections {
|
||||
if sect.VirtualAddress != 0 && sect.Size != 0 &&
|
||||
sect.Characteristics&^IMAGE_SCN_ALIGN_32BYTES == IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE {
|
||||
return uint64(sect.VirtualAddress) + x.imageBase()
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// machoExe is the Mach-O (Apple macOS/iOS) implementation of the exe interface.
|
||||
type machoExe struct {
|
||||
os io.ReadCloser
|
||||
f *macho.File
|
||||
}
|
||||
|
||||
func (x *machoExe) Close() error {
|
||||
return x.os.Close()
|
||||
}
|
||||
|
||||
func (x *machoExe) ArchName() string {
|
||||
return cleanMachoArch(x.f.Cpu)
|
||||
}
|
||||
|
||||
func cleanMachoArch(cpu macho.Cpu) string {
|
||||
return strings.TrimPrefix(strings.ToLower(cpu.String()), "cpu")
|
||||
}
|
||||
|
||||
func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) {
|
||||
for _, load := range x.f.Loads {
|
||||
seg, ok := load.(*macho.Segment)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if seg.Addr <= addr && addr <= seg.Addr+seg.Filesz-1 {
|
||||
if seg.Name == "__PAGEZERO" {
|
||||
continue
|
||||
}
|
||||
n := seg.Addr + seg.Filesz - addr
|
||||
if n > size {
|
||||
n = size
|
||||
}
|
||||
data := make([]byte, n)
|
||||
_, err := seg.ReadAt(data, int64(addr-seg.Addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("address not mapped")
|
||||
}
|
||||
|
||||
func (x *machoExe) DataStart() uint64 {
|
||||
// Look for section named "__go_buildinfo".
|
||||
for _, sec := range x.f.Sections {
|
||||
if sec.Name == "__go_buildinfo" {
|
||||
return sec.Addr
|
||||
}
|
||||
}
|
||||
// Try the first non-empty writable segment.
|
||||
const RW = 3
|
||||
for _, load := range x.f.Loads {
|
||||
seg, ok := load.(*macho.Segment)
|
||||
if ok && seg.Addr != 0 && seg.Filesz != 0 && seg.Prot == RW && seg.Maxprot == RW {
|
||||
return seg.Addr
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/*
|
||||
// xcoffExe is the XCOFF (AIX eXtended COFF) implementation of the exe interface.
|
||||
type xcoffExe struct {
|
||||
os *os.File
|
||||
f *xcoff.File
|
||||
}
|
||||
|
||||
func (x *xcoffExe) Close() error {
|
||||
return x.os.Close()
|
||||
}
|
||||
|
||||
func (x *xcoffExe) ReadData(addr, size uint64) ([]byte, error) {
|
||||
for _, sect := range x.f.Sections {
|
||||
if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) {
|
||||
n := uint64(sect.VirtualAddress+sect.Size) - addr
|
||||
if n > size {
|
||||
n = size
|
||||
}
|
||||
data := make([]byte, n)
|
||||
_, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("address not mapped")
|
||||
}
|
||||
|
||||
func (x *xcoffExe) DataStart() uint64 {
|
||||
return x.f.SectionByType(xcoff.STYP_DATA).VirtualAddress
|
||||
}
|
||||
*/
|
||||
@@ -1,43 +0,0 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_cleanElfArch(t *testing.T) {
|
||||
tests := []struct {
|
||||
machine elf.Machine
|
||||
want string
|
||||
}{
|
||||
{
|
||||
machine: elf.EM_X86_64,
|
||||
want: "x86_64",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.machine.String(), func(t *testing.T) {
|
||||
assert.Equalf(t, test.want, cleanElfArch(test.machine), "cleanElfArch(%v)", test.machine)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_cleanMachoArch(t *testing.T) {
|
||||
tests := []struct {
|
||||
cpu macho.Cpu
|
||||
want string
|
||||
}{
|
||||
{
|
||||
cpu: macho.CpuAmd64,
|
||||
want: "amd64",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.cpu.String(), func(t *testing.T) {
|
||||
assert.Equalf(t, test.want, cleanMachoArch(test.cpu), "cleanMachoArch(%v)", test.cpu)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
xcoff
|
||||
-----
|
||||
|
||||
The code in this package comes from: https://github.com/golang/go/tree/master/src/internal/xcoff -- it was copied over to add support for [xcoff](https://en.wikipedia.org/wiki/XCOFF) binaries. Golang keeps this package as internal, forbidding its external use.
|
||||
@@ -0,0 +1,688 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package xcoff implements access to XCOFF (Extended Common Object File Format) files.
|
||||
|
||||
//nolint //this is an internal golang lib
|
||||
package xcoff
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SectionHeader holds information about an XCOFF section header.
|
||||
type SectionHeader struct {
|
||||
Name string
|
||||
VirtualAddress uint64
|
||||
Size uint64
|
||||
Type uint32
|
||||
Relptr uint64
|
||||
Nreloc uint32
|
||||
}
|
||||
|
||||
type Section struct {
|
||||
SectionHeader
|
||||
Relocs []Reloc
|
||||
io.ReaderAt
|
||||
sr *io.SectionReader
|
||||
}
|
||||
|
||||
// AuxiliaryCSect holds information about an XCOFF symbol in an AUX_CSECT entry.
|
||||
type AuxiliaryCSect struct {
|
||||
Length int64
|
||||
StorageMappingClass int
|
||||
SymbolType int
|
||||
}
|
||||
|
||||
// AuxiliaryFcn holds information about an XCOFF symbol in an AUX_FCN entry.
|
||||
type AuxiliaryFcn struct {
|
||||
Size int64
|
||||
}
|
||||
|
||||
type Symbol struct {
|
||||
Name string
|
||||
Value uint64
|
||||
SectionNumber int
|
||||
StorageClass int
|
||||
AuxFcn AuxiliaryFcn
|
||||
AuxCSect AuxiliaryCSect
|
||||
}
|
||||
|
||||
type Reloc struct {
|
||||
VirtualAddress uint64
|
||||
Symbol *Symbol
|
||||
Signed bool
|
||||
InstructionFixed bool
|
||||
Length uint8
|
||||
Type uint8
|
||||
}
|
||||
|
||||
// ImportedSymbol holds information about an imported XCOFF symbol.
|
||||
type ImportedSymbol struct {
|
||||
Name string
|
||||
Library string
|
||||
}
|
||||
|
||||
// FileHeader holds information about an XCOFF file header.
|
||||
type FileHeader struct {
|
||||
TargetMachine uint16
|
||||
}
|
||||
|
||||
// A File represents an open XCOFF file.
|
||||
type File struct {
|
||||
FileHeader
|
||||
Sections []*Section
|
||||
Symbols []*Symbol
|
||||
StringTable []byte
|
||||
LibraryPaths []string
|
||||
|
||||
closer io.Closer
|
||||
}
|
||||
|
||||
// Open opens the named file using os.Open and prepares it for use as an XCOFF binary.
|
||||
func Open(name string) (*File, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ff, err := NewFile(f)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
ff.closer = f
|
||||
return ff, nil
|
||||
}
|
||||
|
||||
// Close closes the File.
|
||||
// If the File was created using NewFile directly instead of Open,
|
||||
// Close has no effect.
|
||||
func (f *File) Close() error {
|
||||
var err error
|
||||
if f.closer != nil {
|
||||
err = f.closer.Close()
|
||||
f.closer = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Section returns the first section with the given name, or nil if no such
|
||||
// section exists.
|
||||
// Xcoff have section's name limited to 8 bytes. Some sections like .gosymtab
|
||||
// can be trunked but this method will still find them.
|
||||
func (f *File) Section(name string) *Section {
|
||||
for _, s := range f.Sections {
|
||||
if s.Name == name || (len(name) > 8 && s.Name == name[:8]) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SectionByType returns the first section in f with the
|
||||
// given type, or nil if there is no such section.
|
||||
func (f *File) SectionByType(typ uint32) *Section {
|
||||
for _, s := range f.Sections {
|
||||
if s.Type == typ {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// cstring converts ASCII byte sequence b to string.
|
||||
// It stops once it finds 0 or reaches end of b.
|
||||
func cstring(b []byte) string {
|
||||
var i int
|
||||
for i = 0; i < len(b) && b[i] != 0; i++ {
|
||||
}
|
||||
return string(b[:i])
|
||||
}
|
||||
|
||||
// getString extracts a string from an XCOFF string table.
|
||||
func getString(st []byte, offset uint32) (string, bool) {
|
||||
if offset < 4 || int(offset) >= len(st) {
|
||||
return "", false
|
||||
}
|
||||
return cstring(st[offset:]), true
|
||||
}
|
||||
|
||||
// NewFile creates a new File for accessing an XCOFF binary in an underlying reader.
|
||||
func NewFile(r io.ReaderAt) (*File, error) {
|
||||
sr := io.NewSectionReader(r, 0, 1<<63-1)
|
||||
// Read XCOFF target machine
|
||||
var magic uint16
|
||||
if err := binary.Read(sr, binary.BigEndian, &magic); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if magic != U802TOCMAGIC && magic != U64_TOCMAGIC {
|
||||
return nil, fmt.Errorf("unrecognised XCOFF magic: 0x%x", magic)
|
||||
}
|
||||
|
||||
f := new(File)
|
||||
f.TargetMachine = magic
|
||||
|
||||
// Read XCOFF file header
|
||||
if _, err := sr.Seek(0, os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var nscns uint16
|
||||
var symptr uint64
|
||||
var nsyms int32
|
||||
var opthdr uint16
|
||||
var hdrsz int
|
||||
switch f.TargetMachine {
|
||||
case U802TOCMAGIC:
|
||||
fhdr := new(FileHeader32)
|
||||
if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nscns = fhdr.Fnscns
|
||||
symptr = uint64(fhdr.Fsymptr)
|
||||
nsyms = fhdr.Fnsyms
|
||||
opthdr = fhdr.Fopthdr
|
||||
hdrsz = FILHSZ_32
|
||||
case U64_TOCMAGIC:
|
||||
fhdr := new(FileHeader64)
|
||||
if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nscns = fhdr.Fnscns
|
||||
symptr = fhdr.Fsymptr
|
||||
nsyms = fhdr.Fnsyms
|
||||
opthdr = fhdr.Fopthdr
|
||||
hdrsz = FILHSZ_64
|
||||
}
|
||||
|
||||
if symptr == 0 || nsyms <= 0 {
|
||||
return nil, fmt.Errorf("no symbol table")
|
||||
}
|
||||
|
||||
// Read string table (located right after symbol table).
|
||||
offset := symptr + uint64(nsyms)*SYMESZ
|
||||
if _, err := sr.Seek(int64(offset), os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The first 4 bytes contain the length (in bytes).
|
||||
var l uint32
|
||||
if err := binary.Read(sr, binary.BigEndian, &l); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if l > 4 {
|
||||
if _, err := sr.Seek(int64(offset), os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.StringTable = make([]byte, l)
|
||||
if _, err := io.ReadFull(sr, f.StringTable); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Read section headers
|
||||
if _, err := sr.Seek(int64(hdrsz)+int64(opthdr), os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Sections = make([]*Section, nscns)
|
||||
for i := 0; i < int(nscns); i++ {
|
||||
var scnptr uint64
|
||||
s := new(Section)
|
||||
switch f.TargetMachine {
|
||||
case U802TOCMAGIC:
|
||||
shdr := new(SectionHeader32)
|
||||
if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Name = cstring(shdr.Sname[:])
|
||||
s.VirtualAddress = uint64(shdr.Svaddr)
|
||||
s.Size = uint64(shdr.Ssize)
|
||||
scnptr = uint64(shdr.Sscnptr)
|
||||
s.Type = shdr.Sflags
|
||||
s.Relptr = uint64(shdr.Srelptr)
|
||||
s.Nreloc = uint32(shdr.Snreloc)
|
||||
case U64_TOCMAGIC:
|
||||
shdr := new(SectionHeader64)
|
||||
if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Name = cstring(shdr.Sname[:])
|
||||
s.VirtualAddress = shdr.Svaddr
|
||||
s.Size = shdr.Ssize
|
||||
scnptr = shdr.Sscnptr
|
||||
s.Type = shdr.Sflags
|
||||
s.Relptr = shdr.Srelptr
|
||||
s.Nreloc = shdr.Snreloc
|
||||
}
|
||||
r2 := r
|
||||
if scnptr == 0 { // .bss must have all 0s
|
||||
r2 = zeroReaderAt{}
|
||||
}
|
||||
s.sr = io.NewSectionReader(r2, int64(scnptr), int64(s.Size))
|
||||
s.ReaderAt = s.sr
|
||||
f.Sections[i] = s
|
||||
}
|
||||
|
||||
// Symbol map needed by relocation
|
||||
var idxToSym = make(map[int]*Symbol)
|
||||
|
||||
// Read symbol table
|
||||
if _, err := sr.Seek(int64(symptr), os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Symbols = make([]*Symbol, 0)
|
||||
for i := 0; i < int(nsyms); i++ {
|
||||
var numaux int
|
||||
var ok, needAuxFcn bool
|
||||
sym := new(Symbol)
|
||||
switch f.TargetMachine {
|
||||
case U802TOCMAGIC:
|
||||
se := new(SymEnt32)
|
||||
if err := binary.Read(sr, binary.BigEndian, se); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
numaux = int(se.Nnumaux)
|
||||
sym.SectionNumber = int(se.Nscnum)
|
||||
sym.StorageClass = int(se.Nsclass)
|
||||
sym.Value = uint64(se.Nvalue)
|
||||
needAuxFcn = se.Ntype&SYM_TYPE_FUNC != 0 && numaux > 1
|
||||
zeroes := binary.BigEndian.Uint32(se.Nname[:4])
|
||||
if zeroes != 0 {
|
||||
sym.Name = cstring(se.Nname[:])
|
||||
} else {
|
||||
offset := binary.BigEndian.Uint32(se.Nname[4:])
|
||||
sym.Name, ok = getString(f.StringTable, offset)
|
||||
if !ok {
|
||||
goto skip
|
||||
}
|
||||
}
|
||||
case U64_TOCMAGIC:
|
||||
se := new(SymEnt64)
|
||||
if err := binary.Read(sr, binary.BigEndian, se); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
numaux = int(se.Nnumaux)
|
||||
sym.SectionNumber = int(se.Nscnum)
|
||||
sym.StorageClass = int(se.Nsclass)
|
||||
sym.Value = se.Nvalue
|
||||
needAuxFcn = se.Ntype&SYM_TYPE_FUNC != 0 && numaux > 1
|
||||
sym.Name, ok = getString(f.StringTable, se.Noffset)
|
||||
if !ok {
|
||||
goto skip
|
||||
}
|
||||
}
|
||||
if sym.StorageClass != C_EXT && sym.StorageClass != C_WEAKEXT && sym.StorageClass != C_HIDEXT {
|
||||
goto skip
|
||||
}
|
||||
// Must have at least one csect auxiliary entry.
|
||||
if numaux < 1 || i+numaux >= int(nsyms) {
|
||||
goto skip
|
||||
}
|
||||
|
||||
if sym.SectionNumber > int(nscns) {
|
||||
goto skip
|
||||
}
|
||||
if sym.SectionNumber == 0 {
|
||||
sym.Value = 0
|
||||
} else {
|
||||
sym.Value -= f.Sections[sym.SectionNumber-1].VirtualAddress
|
||||
}
|
||||
|
||||
idxToSym[i] = sym
|
||||
|
||||
// If this symbol is a function, it must retrieve its size from
|
||||
// its AUX_FCN entry.
|
||||
// It can happen that a function symbol doesn't have any AUX_FCN.
|
||||
// In this case, needAuxFcn is false and their size will be set to 0.
|
||||
if needAuxFcn {
|
||||
switch f.TargetMachine {
|
||||
case U802TOCMAGIC:
|
||||
aux := new(AuxFcn32)
|
||||
if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sym.AuxFcn.Size = int64(aux.Xfsize)
|
||||
case U64_TOCMAGIC:
|
||||
aux := new(AuxFcn64)
|
||||
if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sym.AuxFcn.Size = int64(aux.Xfsize)
|
||||
}
|
||||
}
|
||||
|
||||
// Read csect auxiliary entry (by convention, it is the last).
|
||||
if !needAuxFcn {
|
||||
if _, err := sr.Seek(int64(numaux-1)*SYMESZ, os.SEEK_CUR); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
i += numaux
|
||||
numaux = 0
|
||||
switch f.TargetMachine {
|
||||
case U802TOCMAGIC:
|
||||
aux := new(AuxCSect32)
|
||||
if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
|
||||
sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
|
||||
sym.AuxCSect.Length = int64(aux.Xscnlen)
|
||||
case U64_TOCMAGIC:
|
||||
aux := new(AuxCSect64)
|
||||
if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
|
||||
sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
|
||||
sym.AuxCSect.Length = int64(aux.Xscnlenhi)<<32 | int64(aux.Xscnlenlo)
|
||||
}
|
||||
f.Symbols = append(f.Symbols, sym)
|
||||
skip:
|
||||
i += numaux // Skip auxiliary entries
|
||||
if _, err := sr.Seek(int64(numaux)*SYMESZ, os.SEEK_CUR); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Read relocations
|
||||
// Only for .data or .text section
|
||||
for _, sect := range f.Sections {
|
||||
if sect.Type != STYP_TEXT && sect.Type != STYP_DATA {
|
||||
continue
|
||||
}
|
||||
sect.Relocs = make([]Reloc, sect.Nreloc)
|
||||
if sect.Relptr == 0 {
|
||||
continue
|
||||
}
|
||||
if _, err := sr.Seek(int64(sect.Relptr), os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := uint32(0); i < sect.Nreloc; i++ {
|
||||
switch f.TargetMachine {
|
||||
case U802TOCMAGIC:
|
||||
rel := new(Reloc32)
|
||||
if err := binary.Read(sr, binary.BigEndian, rel); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sect.Relocs[i].VirtualAddress = uint64(rel.Rvaddr)
|
||||
sect.Relocs[i].Symbol = idxToSym[int(rel.Rsymndx)]
|
||||
sect.Relocs[i].Type = rel.Rtype
|
||||
sect.Relocs[i].Length = rel.Rsize&0x3F + 1
|
||||
|
||||
if rel.Rsize&0x80 != 0 {
|
||||
sect.Relocs[i].Signed = true
|
||||
}
|
||||
if rel.Rsize&0x40 != 0 {
|
||||
sect.Relocs[i].InstructionFixed = true
|
||||
}
|
||||
|
||||
case U64_TOCMAGIC:
|
||||
rel := new(Reloc64)
|
||||
if err := binary.Read(sr, binary.BigEndian, rel); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sect.Relocs[i].VirtualAddress = rel.Rvaddr
|
||||
sect.Relocs[i].Symbol = idxToSym[int(rel.Rsymndx)]
|
||||
sect.Relocs[i].Type = rel.Rtype
|
||||
sect.Relocs[i].Length = rel.Rsize&0x3F + 1
|
||||
if rel.Rsize&0x80 != 0 {
|
||||
sect.Relocs[i].Signed = true
|
||||
}
|
||||
if rel.Rsize&0x40 != 0 {
|
||||
sect.Relocs[i].InstructionFixed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// zeroReaderAt is ReaderAt that reads 0s.
|
||||
type zeroReaderAt struct{}
|
||||
|
||||
// ReadAt writes len(p) 0s into p.
|
||||
func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
for i := range p {
|
||||
p[i] = 0
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Data reads and returns the contents of the XCOFF section s.
|
||||
func (s *Section) Data() ([]byte, error) {
|
||||
dat := make([]byte, s.sr.Size())
|
||||
n, err := s.sr.ReadAt(dat, 0)
|
||||
if n == len(dat) {
|
||||
err = nil
|
||||
}
|
||||
return dat[:n], err
|
||||
}
|
||||
|
||||
// CSect reads and returns the contents of a csect.
|
||||
// func (f *File) CSect(name string) []byte {
|
||||
// for _, sym := range f.Symbols {
|
||||
// if sym.Name == name && sym.AuxCSect.SymbolType == XTY_SD {
|
||||
// if i := sym.SectionNumber - 1; 0 <= i && i < len(f.Sections) {
|
||||
// s := f.Sections[i]
|
||||
// if sym.Value+uint64(sym.AuxCSect.Length) <= s.Size {
|
||||
// dat := make([]byte, sym.AuxCSect.Length)
|
||||
// _, err := s.sr.ReadAt(dat, int64(sym.Value))
|
||||
// if err != nil {
|
||||
// return nil
|
||||
// }
|
||||
// return dat
|
||||
// }
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
// // There are many other DWARF sections, but these
|
||||
// // are the ones the debug/dwarf package uses.
|
||||
// // Don't bother loading others.
|
||||
// var subtypes = [...]uint32{SSUBTYP_DWABREV, SSUBTYP_DWINFO, SSUBTYP_DWLINE, SSUBTYP_DWRNGES, SSUBTYP_DWSTR}
|
||||
// var dat [len(subtypes)][]byte
|
||||
// for i, subtype := range subtypes {
|
||||
// s := f.SectionByType(STYP_DWARF | subtype)
|
||||
// if s != nil {
|
||||
// b, err := s.Data()
|
||||
// if err != nil && uint64(len(b)) < s.Size {
|
||||
// return nil, err
|
||||
// }
|
||||
// dat[i] = b
|
||||
// }
|
||||
// }
|
||||
|
||||
// abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
|
||||
// return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
|
||||
// }
|
||||
|
||||
// readImportID returns the import file IDs stored inside the .loader section.
|
||||
// Library name pattern is either path/base/member or base/member
|
||||
func (f *File) readImportIDs(s *Section) ([]string, error) {
|
||||
// Read loader header
|
||||
if _, err := s.sr.Seek(0, os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var istlen uint32
|
||||
var nimpid int32
|
||||
var impoff uint64
|
||||
switch f.TargetMachine {
|
||||
case U802TOCMAGIC:
|
||||
lhdr := new(LoaderHeader32)
|
||||
if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
istlen = lhdr.Listlen
|
||||
nimpid = lhdr.Lnimpid
|
||||
impoff = uint64(lhdr.Limpoff)
|
||||
case U64_TOCMAGIC:
|
||||
lhdr := new(LoaderHeader64)
|
||||
if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
istlen = lhdr.Listlen
|
||||
nimpid = lhdr.Lnimpid
|
||||
impoff = lhdr.Limpoff
|
||||
}
|
||||
|
||||
// Read loader import file ID table
|
||||
if _, err := s.sr.Seek(int64(impoff), os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
table := make([]byte, istlen)
|
||||
if _, err := io.ReadFull(s.sr, table); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
offset := 0
|
||||
// First import file ID is the default LIBPATH value
|
||||
libpath := cstring(table[offset:])
|
||||
f.LibraryPaths = strings.Split(libpath, ":")
|
||||
offset += len(libpath) + 3 // 3 null bytes
|
||||
all := make([]string, 0)
|
||||
for i := 1; i < int(nimpid); i++ {
|
||||
impidpath := cstring(table[offset:])
|
||||
offset += len(impidpath) + 1
|
||||
impidbase := cstring(table[offset:])
|
||||
offset += len(impidbase) + 1
|
||||
impidmem := cstring(table[offset:])
|
||||
offset += len(impidmem) + 1
|
||||
var path string
|
||||
if len(impidpath) > 0 {
|
||||
path = impidpath + "/" + impidbase + "/" + impidmem
|
||||
} else {
|
||||
path = impidbase + "/" + impidmem
|
||||
}
|
||||
all = append(all, path)
|
||||
}
|
||||
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// ImportedSymbols returns the names of all symbols
|
||||
// referred to by the binary f that are expected to be
|
||||
// satisfied by other libraries at dynamic load time.
|
||||
// It does not return weak symbols.
|
||||
func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
|
||||
s := f.SectionByType(STYP_LOADER)
|
||||
if s == nil {
|
||||
return nil, nil
|
||||
}
|
||||
// Read loader header
|
||||
if _, err := s.sr.Seek(0, os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var stlen uint32
|
||||
var stoff uint64
|
||||
var nsyms int32
|
||||
var symoff uint64
|
||||
switch f.TargetMachine {
|
||||
case U802TOCMAGIC:
|
||||
lhdr := new(LoaderHeader32)
|
||||
if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stlen = lhdr.Lstlen
|
||||
stoff = uint64(lhdr.Lstoff)
|
||||
nsyms = lhdr.Lnsyms
|
||||
symoff = LDHDRSZ_32
|
||||
case U64_TOCMAGIC:
|
||||
lhdr := new(LoaderHeader64)
|
||||
if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stlen = lhdr.Lstlen
|
||||
stoff = lhdr.Lstoff
|
||||
nsyms = lhdr.Lnsyms
|
||||
symoff = lhdr.Lsymoff
|
||||
}
|
||||
|
||||
// Read loader section string table
|
||||
if _, err := s.sr.Seek(int64(stoff), os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st := make([]byte, stlen)
|
||||
if _, err := io.ReadFull(s.sr, st); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read imported libraries
|
||||
libs, err := f.readImportIDs(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read loader symbol table
|
||||
if _, err := s.sr.Seek(int64(symoff), os.SEEK_SET); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
all := make([]ImportedSymbol, 0)
|
||||
for i := 0; i < int(nsyms); i++ {
|
||||
var name string
|
||||
var ifile int32
|
||||
var ok bool
|
||||
switch f.TargetMachine {
|
||||
case U802TOCMAGIC:
|
||||
ldsym := new(LoaderSymbol32)
|
||||
if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ldsym.Lsmtype&0x40 == 0 {
|
||||
continue // Imported symbols only
|
||||
}
|
||||
zeroes := binary.BigEndian.Uint32(ldsym.Lname[:4])
|
||||
if zeroes != 0 {
|
||||
name = cstring(ldsym.Lname[:])
|
||||
} else {
|
||||
offset := binary.BigEndian.Uint32(ldsym.Lname[4:])
|
||||
name, ok = getString(st, offset)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
ifile = ldsym.Lifile
|
||||
case U64_TOCMAGIC:
|
||||
ldsym := new(LoaderSymbol64)
|
||||
if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ldsym.Lsmtype&0x40 == 0 {
|
||||
continue // Imported symbols only
|
||||
}
|
||||
name, ok = getString(st, ldsym.Loffset)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
ifile = ldsym.Lifile
|
||||
}
|
||||
var sym ImportedSymbol
|
||||
sym.Name = name
|
||||
if ifile >= 1 && int(ifile) <= len(libs) {
|
||||
sym.Library = libs[ifile-1]
|
||||
}
|
||||
all = append(all, sym)
|
||||
}
|
||||
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// ImportedLibraries returns the names of all libraries
|
||||
// referred to by the binary f that are expected to be
|
||||
// linked with the binary at dynamic link time.
|
||||
func (f *File) ImportedLibraries() ([]string, error) {
|
||||
s := f.SectionByType(STYP_LOADER)
|
||||
if s == nil {
|
||||
return nil, nil
|
||||
}
|
||||
all, err := f.readImportIDs(s)
|
||||
return all, err
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xcoff
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type fileTest struct {
|
||||
file string
|
||||
hdr FileHeader
|
||||
sections []*SectionHeader
|
||||
needed []string
|
||||
}
|
||||
|
||||
var fileTests = []fileTest{
|
||||
{
|
||||
"testdata/gcc-ppc32-aix-dwarf2-exec",
|
||||
FileHeader{U802TOCMAGIC},
|
||||
[]*SectionHeader{
|
||||
{".text", 0x10000290, 0x00000bbd, STYP_TEXT, 0x7ae6, 0x36},
|
||||
{".data", 0x20000e4d, 0x00000437, STYP_DATA, 0x7d02, 0x2b},
|
||||
{".bss", 0x20001284, 0x0000021c, STYP_BSS, 0, 0},
|
||||
{".loader", 0x00000000, 0x000004b3, STYP_LOADER, 0, 0},
|
||||
{".dwline", 0x00000000, 0x000000df, STYP_DWARF | SSUBTYP_DWLINE, 0x7eb0, 0x7},
|
||||
{".dwinfo", 0x00000000, 0x00000314, STYP_DWARF | SSUBTYP_DWINFO, 0x7ef6, 0xa},
|
||||
{".dwabrev", 0x00000000, 0x000000d6, STYP_DWARF | SSUBTYP_DWABREV, 0, 0},
|
||||
{".dwarnge", 0x00000000, 0x00000020, STYP_DWARF | SSUBTYP_DWARNGE, 0x7f5a, 0x2},
|
||||
{".dwloc", 0x00000000, 0x00000074, STYP_DWARF | SSUBTYP_DWLOC, 0, 0},
|
||||
{".debug", 0x00000000, 0x00005e4f, STYP_DEBUG, 0, 0},
|
||||
},
|
||||
[]string{"libc.a/shr.o"},
|
||||
},
|
||||
{
|
||||
"testdata/gcc-ppc64-aix-dwarf2-exec",
|
||||
FileHeader{U64_TOCMAGIC},
|
||||
[]*SectionHeader{
|
||||
{".text", 0x10000480, 0x00000afd, STYP_TEXT, 0x8322, 0x34},
|
||||
{".data", 0x20000f7d, 0x000002f3, STYP_DATA, 0x85fa, 0x25},
|
||||
{".bss", 0x20001270, 0x00000428, STYP_BSS, 0, 0},
|
||||
{".loader", 0x00000000, 0x00000535, STYP_LOADER, 0, 0},
|
||||
{".dwline", 0x00000000, 0x000000b4, STYP_DWARF | SSUBTYP_DWLINE, 0x8800, 0x4},
|
||||
{".dwinfo", 0x00000000, 0x0000036a, STYP_DWARF | SSUBTYP_DWINFO, 0x8838, 0x7},
|
||||
{".dwabrev", 0x00000000, 0x000000b5, STYP_DWARF | SSUBTYP_DWABREV, 0, 0},
|
||||
{".dwarnge", 0x00000000, 0x00000040, STYP_DWARF | SSUBTYP_DWARNGE, 0x889a, 0x2},
|
||||
{".dwloc", 0x00000000, 0x00000062, STYP_DWARF | SSUBTYP_DWLOC, 0, 0},
|
||||
{".debug", 0x00000000, 0x00006605, STYP_DEBUG, 0, 0},
|
||||
},
|
||||
[]string{"libc.a/shr_64.o"},
|
||||
},
|
||||
}
|
||||
|
||||
func TestOpen(t *testing.T) {
|
||||
for i := range fileTests {
|
||||
tt := &fileTests[i]
|
||||
|
||||
f, err := Open(tt.file)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
|
||||
t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
|
||||
continue
|
||||
}
|
||||
|
||||
for i, sh := range f.Sections {
|
||||
if i >= len(tt.sections) {
|
||||
break
|
||||
}
|
||||
have := &sh.SectionHeader
|
||||
want := tt.sections[i]
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
|
||||
}
|
||||
}
|
||||
tn := len(tt.sections)
|
||||
fn := len(f.Sections)
|
||||
if tn != fn {
|
||||
t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
|
||||
}
|
||||
tl := tt.needed
|
||||
fl, err := f.ImportedLibraries()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !reflect.DeepEqual(tl, fl) {
|
||||
t.Errorf("open %s: loader import = %v, want %v", tt.file, tl, fl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenFailure(t *testing.T) {
|
||||
filename := "file.go" // not an XCOFF object file
|
||||
_, err := Open(filename) // don't crash
|
||||
if err == nil {
|
||||
t.Errorf("open %s: succeeded unexpectedly", filename)
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,373 @@
|
||||
// The code in this package comes from:
|
||||
// https://github.com/golang/go/tree/master/src/internal/xcoff
|
||||
// it was copied over to add support for xcoff binaries.
|
||||
// Golang keeps this package as internal, forbidding its external use.
|
||||
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//nolint // this is an internal golang lib
|
||||
package xcoff
|
||||
|
||||
// File Header.
|
||||
type FileHeader32 struct {
|
||||
Fmagic uint16 // Target machine
|
||||
Fnscns uint16 // Number of sections
|
||||
Ftimedat int32 // Time and date of file creation
|
||||
Fsymptr uint32 // Byte offset to symbol table start
|
||||
Fnsyms int32 // Number of entries in symbol table
|
||||
Fopthdr uint16 // Number of bytes in optional header
|
||||
Fflags uint16 // Flags
|
||||
}
|
||||
|
||||
type FileHeader64 struct {
|
||||
Fmagic uint16 // Target machine
|
||||
Fnscns uint16 // Number of sections
|
||||
Ftimedat int32 // Time and date of file creation
|
||||
Fsymptr uint64 // Byte offset to symbol table start
|
||||
Fopthdr uint16 // Number of bytes in optional header
|
||||
Fflags uint16 // Flags
|
||||
Fnsyms int32 // Number of entries in symbol table
|
||||
}
|
||||
|
||||
const (
|
||||
FILHSZ_32 = 20
|
||||
FILHSZ_64 = 24
|
||||
)
|
||||
const (
|
||||
U802TOCMAGIC = 0737 // AIX 32-bit XCOFF
|
||||
U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF
|
||||
)
|
||||
|
||||
// Flags that describe the type of the object file.
|
||||
const (
|
||||
F_RELFLG = 0x0001
|
||||
F_EXEC = 0x0002
|
||||
F_LNNO = 0x0004
|
||||
F_FDPR_PROF = 0x0010
|
||||
F_FDPR_OPTI = 0x0020
|
||||
F_DSA = 0x0040
|
||||
F_VARPG = 0x0100
|
||||
F_DYNLOAD = 0x1000
|
||||
F_SHROBJ = 0x2000
|
||||
F_LOADONLY = 0x4000
|
||||
)
|
||||
|
||||
// Section Header.
|
||||
type SectionHeader32 struct {
|
||||
Sname [8]byte // Section name
|
||||
Spaddr uint32 // Physical address
|
||||
Svaddr uint32 // Virtual address
|
||||
Ssize uint32 // Section size
|
||||
Sscnptr uint32 // Offset in file to raw data for section
|
||||
Srelptr uint32 // Offset in file to relocation entries for section
|
||||
Slnnoptr uint32 // Offset in file to line number entries for section
|
||||
Snreloc uint16 // Number of relocation entries
|
||||
Snlnno uint16 // Number of line number entries
|
||||
Sflags uint32 // Flags to define the section type
|
||||
}
|
||||
|
||||
type SectionHeader64 struct {
|
||||
Sname [8]byte // Section name
|
||||
Spaddr uint64 // Physical address
|
||||
Svaddr uint64 // Virtual address
|
||||
Ssize uint64 // Section size
|
||||
Sscnptr uint64 // Offset in file to raw data for section
|
||||
Srelptr uint64 // Offset in file to relocation entries for section
|
||||
Slnnoptr uint64 // Offset in file to line number entries for section
|
||||
Snreloc uint32 // Number of relocation entries
|
||||
Snlnno uint32 // Number of line number entries
|
||||
Sflags uint32 // Flags to define the section type
|
||||
Spad uint32 // Needs to be 72 bytes long
|
||||
}
|
||||
|
||||
// Flags defining the section type.
|
||||
const (
|
||||
STYP_DWARF = 0x0010
|
||||
STYP_TEXT = 0x0020
|
||||
STYP_DATA = 0x0040
|
||||
STYP_BSS = 0x0080
|
||||
STYP_EXCEPT = 0x0100
|
||||
STYP_INFO = 0x0200
|
||||
STYP_TDATA = 0x0400
|
||||
STYP_TBSS = 0x0800
|
||||
STYP_LOADER = 0x1000
|
||||
STYP_DEBUG = 0x2000
|
||||
STYP_TYPCHK = 0x4000
|
||||
STYP_OVRFLO = 0x8000
|
||||
)
|
||||
const (
|
||||
SSUBTYP_DWINFO = 0x10000 // DWARF info section
|
||||
SSUBTYP_DWLINE = 0x20000 // DWARF line-number section
|
||||
SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section
|
||||
SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section
|
||||
SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section
|
||||
SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section
|
||||
SSUBTYP_DWSTR = 0x70000 // DWARF strings section
|
||||
SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section
|
||||
SSUBTYP_DWLOC = 0x90000 // DWARF location lists section
|
||||
SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section
|
||||
SSUBTYP_DWMAC = 0xB0000 // DWARF macros section
|
||||
)
|
||||
|
||||
// Symbol Table Entry.
|
||||
type SymEnt32 struct {
|
||||
Nname [8]byte // Symbol name
|
||||
Nvalue uint32 // Symbol value
|
||||
Nscnum int16 // Section number of symbol
|
||||
Ntype uint16 // Basic and derived type specification
|
||||
Nsclass int8 // Storage class of symbol
|
||||
Nnumaux int8 // Number of auxiliary entries
|
||||
}
|
||||
|
||||
type SymEnt64 struct {
|
||||
Nvalue uint64 // Symbol value
|
||||
Noffset uint32 // Offset of the name in string table or .debug section
|
||||
Nscnum int16 // Section number of symbol
|
||||
Ntype uint16 // Basic and derived type specification
|
||||
Nsclass int8 // Storage class of symbol
|
||||
Nnumaux int8 // Number of auxiliary entries
|
||||
}
|
||||
|
||||
const SYMESZ = 18
|
||||
|
||||
const (
|
||||
// Nscnum
|
||||
N_DEBUG = -2
|
||||
N_ABS = -1
|
||||
N_UNDEF = 0
|
||||
|
||||
//Ntype
|
||||
SYM_V_INTERNAL = 0x1000
|
||||
SYM_V_HIDDEN = 0x2000
|
||||
SYM_V_PROTECTED = 0x3000
|
||||
SYM_V_EXPORTED = 0x4000
|
||||
SYM_TYPE_FUNC = 0x0020 // is function
|
||||
)
|
||||
|
||||
// Storage Class.
|
||||
const (
|
||||
C_NULL = 0 // Symbol table entry marked for deletion
|
||||
C_EXT = 2 // External symbol
|
||||
C_STAT = 3 // Static symbol
|
||||
C_BLOCK = 100 // Beginning or end of inner block
|
||||
C_FCN = 101 // Beginning or end of function
|
||||
C_FILE = 103 // Source file name and compiler information
|
||||
C_HIDEXT = 107 // Unnamed external symbol
|
||||
C_BINCL = 108 // Beginning of include file
|
||||
C_EINCL = 109 // End of include file
|
||||
C_WEAKEXT = 111 // Weak external symbol
|
||||
C_DWARF = 112 // DWARF symbol
|
||||
C_GSYM = 128 // Global variable
|
||||
C_LSYM = 129 // Automatic variable allocated on stack
|
||||
C_PSYM = 130 // Argument to subroutine allocated on stack
|
||||
C_RSYM = 131 // Register variable
|
||||
C_RPSYM = 132 // Argument to function or procedure stored in register
|
||||
C_STSYM = 133 // Statically allocated symbol
|
||||
C_BCOMM = 135 // Beginning of common block
|
||||
C_ECOML = 136 // Local member of common block
|
||||
C_ECOMM = 137 // End of common block
|
||||
C_DECL = 140 // Declaration of object
|
||||
C_ENTRY = 141 // Alternate entry
|
||||
C_FUN = 142 // Function or procedure
|
||||
C_BSTAT = 143 // Beginning of static block
|
||||
C_ESTAT = 144 // End of static block
|
||||
C_GTLS = 145 // Global thread-local variable
|
||||
C_STTLS = 146 // Static thread-local variable
|
||||
)
|
||||
|
||||
// File Auxiliary Entry
|
||||
type AuxFile64 struct {
|
||||
Xfname [8]byte // Name or offset inside string table
|
||||
Xftype uint8 // Source file string type
|
||||
Xauxtype uint8 // Type of auxiliary entry
|
||||
}
|
||||
|
||||
// Function Auxiliary Entry
|
||||
type AuxFcn32 struct {
|
||||
Xexptr uint32 // File offset to exception table entry
|
||||
Xfsize uint32 // Size of function in bytes
|
||||
Xlnnoptr uint32 // File pointer to line number
|
||||
Xendndx uint32 // Symbol table index of next entry
|
||||
Xpad uint16 // Unused
|
||||
}
|
||||
type AuxFcn64 struct {
|
||||
Xlnnoptr uint64 // File pointer to line number
|
||||
Xfsize uint32 // Size of function in bytes
|
||||
Xendndx uint32 // Symbol table index of next entry
|
||||
Xpad uint8 // Unused
|
||||
Xauxtype uint8 // Type of auxiliary entry
|
||||
}
|
||||
|
||||
type AuxSect64 struct {
|
||||
Xscnlen uint64 // section length
|
||||
Xnreloc uint64 // Num RLDs
|
||||
pad uint8
|
||||
Xauxtype uint8 // Type of auxiliary entry
|
||||
}
|
||||
|
||||
// csect Auxiliary Entry.
|
||||
type AuxCSect32 struct {
|
||||
Xscnlen int32 // Length or symbol table index
|
||||
Xparmhash uint32 // Offset of parameter type-check string
|
||||
Xsnhash uint16 // .typchk section number
|
||||
Xsmtyp uint8 // Symbol alignment and type
|
||||
Xsmclas uint8 // Storage-mapping class
|
||||
Xstab uint32 // Reserved
|
||||
Xsnstab uint16 // Reserved
|
||||
}
|
||||
|
||||
type AuxCSect64 struct {
|
||||
Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index
|
||||
Xparmhash uint32 // Offset of parameter type-check string
|
||||
Xsnhash uint16 // .typchk section number
|
||||
Xsmtyp uint8 // Symbol alignment and type
|
||||
Xsmclas uint8 // Storage-mapping class
|
||||
Xscnlenhi int32 // Upper 4 bytes of length or symbol table index
|
||||
Xpad uint8 // Unused
|
||||
Xauxtype uint8 // Type of auxiliary entry
|
||||
}
|
||||
|
||||
// Auxiliary type
|
||||
// const (
|
||||
// _AUX_EXCEPT = 255
|
||||
// _AUX_FCN = 254
|
||||
// _AUX_SYM = 253
|
||||
// _AUX_FILE = 252
|
||||
// _AUX_CSECT = 251
|
||||
// _AUX_SECT = 250
|
||||
// )
|
||||
|
||||
// Symbol type field.
|
||||
const (
|
||||
XTY_ER = 0 // External reference
|
||||
XTY_SD = 1 // Section definition
|
||||
XTY_LD = 2 // Label definition
|
||||
XTY_CM = 3 // Common csect definition
|
||||
)
|
||||
|
||||
// Defines for File auxiliary definitions: x_ftype field of x_file
|
||||
const (
|
||||
XFT_FN = 0 // Source File Name
|
||||
XFT_CT = 1 // Compile Time Stamp
|
||||
XFT_CV = 2 // Compiler Version Number
|
||||
XFT_CD = 128 // Compiler Defined Information
|
||||
)
|
||||
|
||||
// Storage-mapping class.
|
||||
const (
|
||||
XMC_PR = 0 // Program code
|
||||
XMC_RO = 1 // Read-only constant
|
||||
XMC_DB = 2 // Debug dictionary table
|
||||
XMC_TC = 3 // TOC entry
|
||||
XMC_UA = 4 // Unclassified
|
||||
XMC_RW = 5 // Read/Write data
|
||||
XMC_GL = 6 // Global linkage
|
||||
XMC_XO = 7 // Extended operation
|
||||
XMC_SV = 8 // 32-bit supervisor call descriptor
|
||||
XMC_BS = 9 // BSS class
|
||||
XMC_DS = 10 // Function descriptor
|
||||
XMC_UC = 11 // Unnamed FORTRAN common
|
||||
XMC_TC0 = 15 // TOC anchor
|
||||
XMC_TD = 16 // Scalar data entry in the TOC
|
||||
XMC_SV64 = 17 // 64-bit supervisor call descriptor
|
||||
XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit
|
||||
XMC_TL = 20 // Read/Write thread-local data
|
||||
XMC_UL = 21 // Read/Write thread-local data (.tbss)
|
||||
XMC_TE = 22 // TOC entry
|
||||
)
|
||||
|
||||
// Loader Header.
|
||||
type LoaderHeader32 struct {
|
||||
Lversion int32 // Loader section version number
|
||||
Lnsyms int32 // Number of symbol table entries
|
||||
Lnreloc int32 // Number of relocation table entries
|
||||
Listlen uint32 // Length of import file ID string table
|
||||
Lnimpid int32 // Number of import file IDs
|
||||
Limpoff uint32 // Offset to start of import file IDs
|
||||
Lstlen uint32 // Length of string table
|
||||
Lstoff uint32 // Offset to start of string table
|
||||
}
|
||||
|
||||
type LoaderHeader64 struct {
|
||||
Lversion int32 // Loader section version number
|
||||
Lnsyms int32 // Number of symbol table entries
|
||||
Lnreloc int32 // Number of relocation table entries
|
||||
Listlen uint32 // Length of import file ID string table
|
||||
Lnimpid int32 // Number of import file IDs
|
||||
Lstlen uint32 // Length of string table
|
||||
Limpoff uint64 // Offset to start of import file IDs
|
||||
Lstoff uint64 // Offset to start of string table
|
||||
Lsymoff uint64 // Offset to start of symbol table
|
||||
Lrldoff uint64 // Offset to start of relocation entries
|
||||
}
|
||||
|
||||
const (
|
||||
LDHDRSZ_32 = 32
|
||||
LDHDRSZ_64 = 56
|
||||
)
|
||||
|
||||
// Loader Symbol.
|
||||
type LoaderSymbol32 struct {
|
||||
Lname [8]byte // Symbol name or byte offset into string table
|
||||
Lvalue uint32 // Address field
|
||||
Lscnum int16 // Section number containing symbol
|
||||
Lsmtype int8 // Symbol type, export, import flags
|
||||
Lsmclas int8 // Symbol storage class
|
||||
Lifile int32 // Import file ID; ordinal of import file IDs
|
||||
Lparm uint32 // Parameter type-check field
|
||||
}
|
||||
|
||||
type LoaderSymbol64 struct {
|
||||
Lvalue uint64 // Address field
|
||||
Loffset uint32 // Byte offset into string table of symbol name
|
||||
Lscnum int16 // Section number containing symbol
|
||||
Lsmtype int8 // Symbol type, export, import flags
|
||||
Lsmclas int8 // Symbol storage class
|
||||
Lifile int32 // Import file ID; ordinal of import file IDs
|
||||
Lparm uint32 // Parameter type-check field
|
||||
}
|
||||
|
||||
type Reloc32 struct {
|
||||
Rvaddr uint32 // (virtual) address of reference
|
||||
Rsymndx uint32 // Index into symbol table
|
||||
Rsize uint8 // Sign and reloc bit len
|
||||
Rtype uint8 // Toc relocation type
|
||||
}
|
||||
|
||||
type Reloc64 struct {
|
||||
Rvaddr uint64 // (virtual) address of reference
|
||||
Rsymndx uint32 // Index into symbol table
|
||||
Rsize uint8 // Sign and reloc bit len
|
||||
Rtype uint8 // Toc relocation type
|
||||
}
|
||||
|
||||
const (
|
||||
R_POS = 0x00 // A(sym) Positive Relocation
|
||||
R_NEG = 0x01 // -A(sym) Negative Relocation
|
||||
R_REL = 0x02 // A(sym-*) Relative to self
|
||||
R_TOC = 0x03 // A(sym-TOC) Relative to TOC
|
||||
R_TRL = 0x12 // A(sym-TOC) TOC Relative indirect load.
|
||||
|
||||
R_TRLA = 0x13 // A(sym-TOC) TOC Rel load address. modifiable inst
|
||||
R_GL = 0x05 // A(external TOC of sym) Global Linkage
|
||||
R_TCL = 0x06 // A(local TOC of sym) Local object TOC address
|
||||
R_RL = 0x0C // A(sym) Pos indirect load. modifiable instruction
|
||||
R_RLA = 0x0D // A(sym) Pos Load Address. modifiable instruction
|
||||
R_REF = 0x0F // AL0(sym) Non relocating ref. No garbage collect
|
||||
R_BA = 0x08 // A(sym) Branch absolute. Cannot modify instruction
|
||||
R_RBA = 0x18 // A(sym) Branch absolute. modifiable instruction
|
||||
R_BR = 0x0A // A(sym-*) Branch rel to self. non modifiable
|
||||
R_RBR = 0x1A // A(sym-*) Branch rel to self. modifiable instr
|
||||
|
||||
R_TLS = 0x20 // General-dynamic reference to TLS symbol
|
||||
R_TLS_IE = 0x21 // Initial-exec reference to TLS symbol
|
||||
R_TLS_LD = 0x22 // Local-dynamic reference to TLS symbol
|
||||
R_TLS_LE = 0x23 // Local-exec reference to TLS symbol
|
||||
R_TLSM = 0x24 // Module reference to TLS symbol
|
||||
R_TLSML = 0x25 // Module reference to local (own) module
|
||||
|
||||
R_TOCU = 0x30 // Relative to TOC - high order bits
|
||||
R_TOCL = 0x31 // Relative to TOC - low order bits
|
||||
)
|
||||
@@ -1,26 +1,52 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/golang/internal/xcoff"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
const (
|
||||
packageIdentifier = "dep"
|
||||
replaceIdentifier = "=>"
|
||||
const GOARCH = "GOARCH"
|
||||
|
||||
var (
|
||||
// errUnrecognizedFormat is returned when a given executable file doesn't
|
||||
// appear to be in a known format, or it breaks the rules of that format,
|
||||
// or when there are I/O errors reading the file.
|
||||
errUnrecognizedFormat = errors.New("unrecognized file format")
|
||||
)
|
||||
|
||||
type exeOpener func(file io.ReadCloser) ([]exe, error)
|
||||
func makeGoMainPackage(mod *debug.BuildInfo, arch string, location source.Location) pkg.Package {
|
||||
gbs := getBuildSettings(mod.Settings)
|
||||
main := newGoBinaryPackage(&mod.Main, mod.GoVersion, arch, location, gbs)
|
||||
main.Version = ""
|
||||
|
||||
if v, ok := gbs["vcs.revision"]; ok {
|
||||
main.Version = v
|
||||
}
|
||||
|
||||
return main
|
||||
}
|
||||
|
||||
func newGoBinaryPackage(dep *debug.Module, goVersion, architecture string, location source.Location, buildSettings map[string]string) pkg.Package {
|
||||
if dep.Replace != nil {
|
||||
dep = dep.Replace
|
||||
}
|
||||
|
||||
func newGoBinaryPackage(name, version, h1Digest, goVersion, architecture string, location source.Location) pkg.Package {
|
||||
p := pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
FoundBy: catalogerName,
|
||||
Name: dep.Path,
|
||||
Version: dep.Version,
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: []source.Location{
|
||||
@@ -29,8 +55,9 @@ func newGoBinaryPackage(name, version, h1Digest, goVersion, architecture string,
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
GoCompiledVersion: goVersion,
|
||||
H1Digest: h1Digest,
|
||||
H1Digest: dep.Sum,
|
||||
Architecture: architecture,
|
||||
BuildSettings: buildSettings,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -39,49 +66,128 @@ func newGoBinaryPackage(name, version, h1Digest, goVersion, architecture string,
|
||||
return p
|
||||
}
|
||||
|
||||
func parseGoBin(location source.Location, reader io.ReadCloser, opener exeOpener) (pkgs []pkg.Package, err error) {
|
||||
var exes []exe
|
||||
// it has been found that there are stdlib paths within openExe that can panic. We want to prevent this behavior
|
||||
// bubbling up and halting execution. For this reason we try to recover from any panic and return an error.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("recovered from panic while parse go binary at %q: %+v", location.RealPath, r)
|
||||
}
|
||||
}()
|
||||
|
||||
// Identify if bin was compiled by go
|
||||
exes, err = opener(reader)
|
||||
if err != nil {
|
||||
return pkgs, err
|
||||
// getArchs finds a binary architecture by two ways:
|
||||
// 1) reading build info from binaries compiled by go1.18+
|
||||
// 2) reading file headers from binaries compiled by < go1.18
|
||||
func getArchs(readers []io.ReaderAt, builds []*debug.BuildInfo) []string {
|
||||
if len(readers) != len(builds) {
|
||||
log.Warnf("golang cataloger: bin parsing: number of builds and readers doesn't match")
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, x := range exes {
|
||||
goVersion, mod := findVers(x)
|
||||
pkgs = append(pkgs, buildGoPkgInfo(location, mod, goVersion, x.ArchName())...)
|
||||
if len(readers) == 0 || len(builds) == 0 {
|
||||
log.Warnf("golang cataloger: bin parsing: %d readers and %d build info items", len(readers), len(builds))
|
||||
return nil
|
||||
}
|
||||
return pkgs, err
|
||||
}
|
||||
|
||||
func buildGoPkgInfo(location source.Location, mod, goVersion, arch string) []pkg.Package {
|
||||
pkgsSlice := make([]pkg.Package, 0)
|
||||
scanner := bufio.NewScanner(strings.NewReader(mod))
|
||||
archs := make([]string, len(builds))
|
||||
for i, build := range builds {
|
||||
archs[i] = getGOARCH(build.Settings)
|
||||
}
|
||||
|
||||
// filter mod dependencies: [dep, name, version, sha]
|
||||
for scanner.Scan() {
|
||||
fields := strings.Fields(scanner.Text())
|
||||
// if architecture was found via build settings return
|
||||
if archs[0] != "" {
|
||||
return archs
|
||||
}
|
||||
|
||||
// must have dep, name, version, sha
|
||||
if len(fields) < 4 {
|
||||
for i, r := range readers {
|
||||
a, err := getGOARCHFromBin(r)
|
||||
if err != nil {
|
||||
log.Warnf("golang cataloger: bin parsing: getting arch from binary: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if fields[0] == packageIdentifier || fields[0] == replaceIdentifier {
|
||||
name := fields[1]
|
||||
version := fields[2]
|
||||
h1Digest := fields[3]
|
||||
pkgsSlice = append(pkgsSlice, newGoBinaryPackage(name, version, h1Digest, goVersion, arch, location))
|
||||
archs[i] = a
|
||||
}
|
||||
return archs
|
||||
}
|
||||
|
||||
func getGOARCH(settings []debug.BuildSetting) string {
|
||||
for _, s := range settings {
|
||||
if s.Key == GOARCH {
|
||||
return s.Value
|
||||
}
|
||||
}
|
||||
|
||||
return pkgsSlice
|
||||
return ""
|
||||
}
|
||||
|
||||
func getGOARCHFromBin(r io.ReaderAt) (string, error) {
|
||||
// Read the first bytes of the file to identify the format, then delegate to
|
||||
// a format-specific function to load segment and section headers.
|
||||
ident := make([]byte, 16)
|
||||
if n, err := r.ReadAt(ident, 0); n < len(ident) || err != nil {
|
||||
return "", fmt.Errorf("unrecognized file format: %w", err)
|
||||
}
|
||||
|
||||
var arch string
|
||||
switch {
|
||||
case bytes.HasPrefix(ident, []byte("\x7FELF")):
|
||||
f, err := elf.NewFile(r)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unrecognized file format: %w", err)
|
||||
}
|
||||
arch = f.Machine.String()
|
||||
case bytes.HasPrefix(ident, []byte("MZ")):
|
||||
f, err := pe.NewFile(r)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unrecognized file format: %w", err)
|
||||
}
|
||||
arch = fmt.Sprintf("%d", f.Machine)
|
||||
case bytes.HasPrefix(ident, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(ident[1:], []byte("\xFA\xED\xFE")):
|
||||
f, err := macho.NewFile(r)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unrecognized file format: %w", err)
|
||||
}
|
||||
arch = f.Cpu.String()
|
||||
case bytes.HasPrefix(ident, []byte{0x01, 0xDF}) || bytes.HasPrefix(ident, []byte{0x01, 0xF7}):
|
||||
f, err := xcoff.NewFile(r)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unrecognized file format: %w", err)
|
||||
}
|
||||
arch = fmt.Sprintf("%d", f.FileHeader.TargetMachine)
|
||||
default:
|
||||
return "", errUnrecognizedFormat
|
||||
}
|
||||
|
||||
arch = strings.Replace(arch, "EM_", "", 1)
|
||||
arch = strings.Replace(arch, "Cpu", "", 1)
|
||||
arch = strings.ToLower(arch)
|
||||
|
||||
return arch, nil
|
||||
}
|
||||
|
||||
func getBuildSettings(settings []debug.BuildSetting) map[string]string {
|
||||
m := make(map[string]string)
|
||||
for _, s := range settings {
|
||||
m[s.Key] = s.Value
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func buildGoPkgInfo(location source.Location, mod *debug.BuildInfo, arch string) []pkg.Package {
|
||||
var pkgs []pkg.Package
|
||||
if mod == nil {
|
||||
return pkgs
|
||||
}
|
||||
|
||||
for _, dep := range mod.Deps {
|
||||
if dep == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
pkgs = append(pkgs, newGoBinaryPackage(dep, mod.GoVersion, arch, location, nil))
|
||||
}
|
||||
|
||||
// NOTE(jonasagx): this use happened originally while creating unit tests. It might never
|
||||
// happen in the wild, but I kept it as a safeguard against empty modules.
|
||||
var empty debug.Module
|
||||
if mod.Main == empty {
|
||||
return pkgs
|
||||
}
|
||||
|
||||
main := makeGoMainPackage(mod, arch, location)
|
||||
pkgs = append(pkgs, main)
|
||||
|
||||
return pkgs
|
||||
}
|
||||
|
||||
@@ -1,37 +1,254 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// make will run the default make target for the given test fixture path
|
||||
func runMakeTarget(t *testing.T, fixtureName string) {
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
fixtureDir := filepath.Join(cwd, "test-fixtures/", fixtureName)
|
||||
|
||||
t.Logf("Generating Fixture in %q", fixtureDir)
|
||||
|
||||
cmd := exec.Command("make")
|
||||
cmd.Dir = fixtureDir
|
||||
|
||||
stderr, err := cmd.StderrPipe()
|
||||
require.NoError(t, err)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = cmd.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
show := func(label string, reader io.ReadCloser) {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
for scanner.Scan() {
|
||||
t.Logf("%s: %s", label, scanner.Text())
|
||||
}
|
||||
}
|
||||
go show("out", stdout)
|
||||
go show("err", stderr)
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
// The program has exited with an exit code != 0
|
||||
|
||||
// This works on both Unix and Windows. Although package
|
||||
// syscall is generally platform dependent, WaitStatus is
|
||||
// defined for both Unix and Windows and in both cases has
|
||||
// an ExitStatus() method with the same signature.
|
||||
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||
if status.ExitStatus() != 0 {
|
||||
t.Fatalf("failed to generate fixture: rc=%d", status.ExitStatus())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("unable to get generate fixture result: %+v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getGOARCHFromBin(t *testing.T) {
|
||||
runMakeTarget(t, "archs")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
filepath string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "pe",
|
||||
filepath: "test-fixtures/archs/binaries/hello-win-amd64",
|
||||
// see: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types
|
||||
expected: strconv.Itoa(0x8664),
|
||||
},
|
||||
{
|
||||
name: "elf-ppc64",
|
||||
filepath: "test-fixtures/archs/binaries/hello-linux-ppc64le",
|
||||
expected: "ppc64",
|
||||
},
|
||||
{
|
||||
name: "mach-o-arm64",
|
||||
filepath: "test-fixtures/archs/binaries/hello-mach-o-arm64",
|
||||
expected: "arm64",
|
||||
},
|
||||
{
|
||||
name: "linux-arm",
|
||||
filepath: "test-fixtures/archs/binaries/hello-linux-arm",
|
||||
expected: "arm",
|
||||
},
|
||||
{
|
||||
name: "xcoff-32bit",
|
||||
filepath: "internal/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec",
|
||||
expected: strconv.Itoa(0x1DF),
|
||||
},
|
||||
{
|
||||
name: "xcoff-64bit",
|
||||
filepath: "internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec",
|
||||
expected: strconv.Itoa(0x1F7),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
f, err := os.Open(tt.filepath)
|
||||
require.NoError(t, err)
|
||||
arch, err := getGOARCHFromBin(f)
|
||||
require.NoError(t, err, "test name: %s", tt.name)
|
||||
assert.Equal(t, tt.expected, arch)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestBuildGoPkgInfo(t *testing.T) {
|
||||
const (
|
||||
goCompiledVersion = "1.17"
|
||||
goCompiledVersion = "1.18"
|
||||
archDetails = "amd64"
|
||||
)
|
||||
buildSettings := map[string]string{
|
||||
"GOARCH": "amd64",
|
||||
"GOOS": "darwin",
|
||||
"GOAMD64": "v1",
|
||||
}
|
||||
|
||||
expectedMain := pkg.Package{
|
||||
Name: "github.com/anchore/syft",
|
||||
FoundBy: catalogerName,
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: []source.Location{
|
||||
{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
BuildSettings: buildSettings,
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
mod string
|
||||
mod *debug.BuildInfo
|
||||
arch string
|
||||
expected []pkg.Package
|
||||
}{
|
||||
{
|
||||
name: "buildGoPkgInfo parses a blank mod string and returns no packages",
|
||||
mod: "",
|
||||
expected: make([]pkg.Package, 0),
|
||||
name: "buildGoPkgInfo parses a nil mod",
|
||||
mod: nil,
|
||||
expected: []pkg.Package(nil),
|
||||
},
|
||||
{
|
||||
name: "buildGoPkgInfo parses a populated mod string and returns packages but no source info",
|
||||
mod: `path github.com/anchore/syft mod github.com/anchore/syft (devel)
|
||||
dep github.com/adrg/xdg v0.2.1 h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=
|
||||
dep github.com/anchore/client-go v0.0.0-20210222170800-9c70f9b80bcf h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=`,
|
||||
name: "buildGoPkgInfo parses a blank mod and returns no packages",
|
||||
mod: &debug.BuildInfo{},
|
||||
expected: []pkg.Package(nil),
|
||||
},
|
||||
{
|
||||
name: "buildGoPkgInfo parses a mod without main module",
|
||||
arch: archDetails,
|
||||
mod: &debug.BuildInfo{
|
||||
GoVersion: goCompiledVersion,
|
||||
Settings: []debug.BuildSetting{
|
||||
{Key: "GOARCH", Value: archDetails},
|
||||
{Key: "GOOS", Value: "darwin"},
|
||||
{Key: "GOAMD64", Value: "v1"},
|
||||
},
|
||||
Deps: []*debug.Module{
|
||||
{
|
||||
Path: "github.com/adrg/xdg",
|
||||
Version: "v0.2.1",
|
||||
Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "github.com/adrg/xdg",
|
||||
FoundBy: catalogerName,
|
||||
Version: "v0.2.1",
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: []source.Location{
|
||||
{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
H1Digest: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "buildGoPkgInfo parses a mod without packages",
|
||||
arch: archDetails,
|
||||
mod: &debug.BuildInfo{
|
||||
GoVersion: goCompiledVersion,
|
||||
Main: debug.Module{Path: "github.com/anchore/syft"},
|
||||
Settings: []debug.BuildSetting{
|
||||
{Key: "GOARCH", Value: archDetails},
|
||||
{Key: "GOOS", Value: "darwin"},
|
||||
{Key: "GOAMD64", Value: "v1"},
|
||||
},
|
||||
},
|
||||
expected: []pkg.Package{expectedMain},
|
||||
},
|
||||
{
|
||||
name: "buildGoPkgInfo parses a populated mod string and returns packages but no source info",
|
||||
arch: archDetails,
|
||||
mod: &debug.BuildInfo{
|
||||
GoVersion: goCompiledVersion,
|
||||
Main: debug.Module{Path: "github.com/anchore/syft"},
|
||||
Settings: []debug.BuildSetting{
|
||||
{Key: "GOARCH", Value: archDetails},
|
||||
{Key: "GOOS", Value: "darwin"},
|
||||
{Key: "GOAMD64", Value: "v1"},
|
||||
},
|
||||
Deps: []*debug.Module{
|
||||
{
|
||||
Path: "github.com/adrg/xdg",
|
||||
Version: "v0.2.1",
|
||||
Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=",
|
||||
},
|
||||
{
|
||||
Path: "github.com/anchore/client-go",
|
||||
Version: "v0.0.0-20210222170800-9c70f9b80bcf",
|
||||
Sum: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "github.com/adrg/xdg",
|
||||
FoundBy: catalogerName,
|
||||
Version: "v0.2.1",
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
@@ -52,6 +269,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Name: "github.com/anchore/client-go",
|
||||
FoundBy: catalogerName,
|
||||
Version: "v0.0.0-20210222170800-9c70f9b80bcf",
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
@@ -70,39 +288,42 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
H1Digest: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=",
|
||||
},
|
||||
},
|
||||
expectedMain,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "buildGoPkgInfo parses a populated mod string and returns packages when a replace directive exists",
|
||||
mod: `path github.com/anchore/test
|
||||
mod github.com/anchore/test (devel)
|
||||
dep golang.org/x/net v0.0.0-20211006190231-62292e806868 h1:KlOXYy8wQWTUJYFgkUI40Lzr06ofg5IRXUK5C7qZt1k=
|
||||
dep golang.org/x/sys v0.0.0-20211006194710-c8a6f5223071 h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=
|
||||
dep golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
=> golang.org/x/term v0.0.0-20210916214954-140adaaadfaf h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=`,
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "golang.org/x/net",
|
||||
Version: "v0.0.0-20211006190231-62292e806868",
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: []source.Location{
|
||||
{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
arch: archDetails,
|
||||
mod: &debug.BuildInfo{
|
||||
GoVersion: goCompiledVersion,
|
||||
Main: debug.Module{Path: "github.com/anchore/syft"},
|
||||
Settings: []debug.BuildSetting{
|
||||
{Key: "GOARCH", Value: archDetails},
|
||||
{Key: "GOOS", Value: "darwin"},
|
||||
{Key: "GOAMD64", Value: "v1"},
|
||||
},
|
||||
Deps: []*debug.Module{
|
||||
{
|
||||
Path: "golang.org/x/sys",
|
||||
Version: "v0.0.0-20211006194710-c8a6f5223071",
|
||||
Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=",
|
||||
},
|
||||
{
|
||||
Path: "golang.org/x/term",
|
||||
Version: "v0.0.0-20210927222741-03fcf44c2211",
|
||||
Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=",
|
||||
Replace: &debug.Module{
|
||||
Path: "golang.org/x/term",
|
||||
Version: "v0.0.0-20210916214954-140adaaadfaf",
|
||||
Sum: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=",
|
||||
},
|
||||
},
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
H1Digest: "h1:KlOXYy8wQWTUJYFgkUI40Lzr06ofg5IRXUK5C7qZt1k=",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "golang.org/x/sys",
|
||||
FoundBy: catalogerName,
|
||||
Version: "v0.0.0-20211006194710-c8a6f5223071",
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
@@ -111,18 +332,15 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
H1Digest: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=",
|
||||
},
|
||||
},
|
||||
H1Digest: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE="}},
|
||||
{
|
||||
Name: "golang.org/x/term",
|
||||
FoundBy: catalogerName,
|
||||
Version: "v0.0.0-20210916214954-140adaaadfaf",
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
@@ -138,9 +356,9 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
H1Digest: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=",
|
||||
},
|
||||
H1Digest: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI="},
|
||||
},
|
||||
expectedMain,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -157,30 +375,8 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
}
|
||||
pkgs := buildGoPkgInfo(location, test.mod, goCompiledVersion, archDetails)
|
||||
pkgs := buildGoPkgInfo(location, test.mod, test.arch)
|
||||
assert.Equal(t, test.expected, pkgs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseGoBin_recoversFromPanic(t *testing.T) {
|
||||
freakOut := func(file io.ReadCloser) ([]exe, error) {
|
||||
panic("baaahhh!")
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
wantPkgs []pkg.Package
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "recovers from panic",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
pkgs, err := parseGoBin(source.NewLocation("some/path"), nil, freakOut)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, pkgs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"debug/buildinfo"
|
||||
"io"
|
||||
"runtime/debug"
|
||||
|
||||
macho "github.com/anchore/go-macholibre"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
)
|
||||
|
||||
// unionReader is a single interface with all reading functions used by golang bin
|
||||
// cataloger.
|
||||
type unionReader interface {
|
||||
io.Reader
|
||||
io.ReaderAt
|
||||
io.Seeker
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// scanFile scans file to try to report the Go and module versions.
|
||||
func scanFile(reader unionReader, filename string) ([]*debug.BuildInfo, []string) {
|
||||
// NOTE: multiple readers are returned to cover universal binaries, which are files
|
||||
// with more than one binary
|
||||
readers, err := getReaders(reader)
|
||||
if err != nil {
|
||||
log.Warnf("golang cataloger: failed to open a binary: %v", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var builds []*debug.BuildInfo
|
||||
for _, r := range readers {
|
||||
bi, err := buildinfo.Read(r)
|
||||
|
||||
// note: the stdlib does not export the error we need to check for
|
||||
if err != nil {
|
||||
if err.Error() == "not a Go executable" {
|
||||
// since the cataloger can only select executables and not distinguish if they are a go-compiled
|
||||
// binary, we should not show warnings/logs in this case.
|
||||
return nil, nil
|
||||
}
|
||||
// in this case we could not read the or parse the file, but not explicitly because it is not a
|
||||
// go-compiled binary (though it still might be).
|
||||
log.Warnf("golang cataloger: failed to read buildinfo (file=%q): %v", filename, err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
builds = append(builds, bi)
|
||||
}
|
||||
|
||||
archs := getArchs(readers, builds)
|
||||
|
||||
return builds, archs
|
||||
}
|
||||
|
||||
// getReaders extracts one or more io.ReaderAt objects representing binaries that can be processed (multiple binaries in the case for multi-architecture binaries).
|
||||
func getReaders(f unionReader) ([]io.ReaderAt, error) {
|
||||
if macho.IsUniversalMachoBinary(f) {
|
||||
machoReaders, err := macho.ExtractReaders(f)
|
||||
if err != nil {
|
||||
log.Debugf("extracting readers: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var readers []io.ReaderAt
|
||||
for _, e := range machoReaders {
|
||||
readers = append(readers, e.Reader)
|
||||
}
|
||||
|
||||
return readers, nil
|
||||
}
|
||||
|
||||
return []io.ReaderAt{f}, nil
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
binaries/
|
||||
@@ -0,0 +1,29 @@
|
||||
DESTINATION=binaries
|
||||
|
||||
all: $(DESTINATION)/hello-mach-o-arm64 $(DESTINATION)/hello-linux-arm $(DESTINATION)/hello-linux-ppc64le $(DESTINATION)/hello-win-amd64
|
||||
|
||||
$(DESTINATION)/hello-mach-o-arm64:
|
||||
mkdir -p $(DESTINATION)
|
||||
GOARCH=arm64 GOOS=darwin ./src/build.sh $(DESTINATION)/hello-mach-o-arm64
|
||||
|
||||
$(DESTINATION)/hello-linux-arm:
|
||||
mkdir -p $(DESTINATION)
|
||||
GOARCH=arm GOOS=linux ./src/build.sh $(DESTINATION)/hello-linux-arm
|
||||
|
||||
$(DESTINATION)/hello-linux-ppc64le:
|
||||
mkdir -p $(DESTINATION)
|
||||
GOARCH=ppc64le GOOS=linux ./src/build.sh $(DESTINATION)/hello-linux-ppc64le
|
||||
|
||||
$(DESTINATION)/hello-win-amd64:
|
||||
mkdir -p $(DESTINATION)
|
||||
GOARCH=amd64 GOOS=windows ./src/build.sh $(DESTINATION)/hello-win-amd64
|
||||
|
||||
# we need a way to determine if CI should bust the test cache based on the source material
|
||||
$(DESTINATION).fingerprint: clean
|
||||
mkdir -p $(DESTINATION)
|
||||
find src -type f -exec sha256sum {} \; | sort | tee /dev/stderr | tee $(DESTINATION).fingerprint
|
||||
sha256sum $(DESTINATION).fingerprint
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(DESTINATION)/*
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
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)
|
||||
# note: gocache override is so we can run docker build not as root in a container without permission issues
|
||||
|
||||
BINARY=$1
|
||||
CTRID=$(docker create -e GOOS="${GOOS}" -e GOARCH="${GOARCH}" -u "$(id -u):$(id -g)" -e GOCACHE=/tmp -w /src golang:1.17 go build -o main main.go)
|
||||
|
||||
function cleanup() {
|
||||
docker rm "${CTRID}"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
set +e
|
||||
|
||||
# note: pwd = parent directory (archs)
|
||||
docker cp "$(pwd)/src" "${CTRID}:/"
|
||||
docker start -a "${CTRID}"
|
||||
docker cp "${CTRID}:/src/main" "$BINARY"
|
||||
@@ -0,0 +1,3 @@
|
||||
module arch/v1
|
||||
|
||||
go 1.17
|
||||
@@ -0,0 +1,5 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
println("свобода!")
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
// This code was copied from the Go std library.
|
||||
// https://github.com/golang/go/blob/master/src/cmd/go/internal/version/version.go
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package version implements the ``go version'' command.
|
||||
package golang
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
// "cmd/go/internal/base"
|
||||
)
|
||||
|
||||
/*
|
||||
var CmdVersion = &base.Command{
|
||||
UsageLine: "go version [-m] [-v] [file ...]",
|
||||
Short: "print Go version",
|
||||
Long: `Version prints the build information for Go executables.
|
||||
|
||||
Go version reports the Go version used to build each of the named
|
||||
executable files.
|
||||
|
||||
If no files are named on the command line, go version prints its own
|
||||
version information.
|
||||
|
||||
If a directory is named, go version walks that directory, recursively,
|
||||
looking for recognized Go binaries and reporting their versions.
|
||||
By default, go version does not report unrecognized files found
|
||||
during a directory scan. The -v flag causes it to report unrecognized files.
|
||||
|
||||
The -m flag causes go version to print each executable's embedded
|
||||
module version information, when available. In the output, the module
|
||||
information consists of multiple lines following the version line, each
|
||||
indented by a leading tab character.
|
||||
|
||||
See also: go doc runtime/debug.BuildInfo.
|
||||
`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
CmdVersion.Run = runVersion // break init cycle
|
||||
}
|
||||
|
||||
var (
|
||||
versionM = CmdVersion.Flag.Bool("m", false, "")
|
||||
versionV = CmdVersion.Flag.Bool("v", false, "")
|
||||
)
|
||||
|
||||
func runVersion(ctx context.Context, cmd *base.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
// If any of this command's flags were passed explicitly, error
|
||||
// out, because they only make sense with arguments.
|
||||
//
|
||||
// Don't error if the flags came from GOFLAGS, since that can be
|
||||
// a reasonable use case. For example, imagine GOFLAGS=-v to
|
||||
// turn "verbose mode" on for all Go commands, which should not
|
||||
// break "go version".
|
||||
var argOnlyFlag string
|
||||
if !base.InGOFLAGS("-m") && *versionM {
|
||||
argOnlyFlag = "-m"
|
||||
} else if !base.InGOFLAGS("-v") && *versionV {
|
||||
argOnlyFlag = "-v"
|
||||
}
|
||||
if argOnlyFlag != "" {
|
||||
fmt.Fprintf(os.Stderr, "go: 'go version' only accepts %s flag with arguments\n", argOnlyFlag)
|
||||
base.SetExitStatus(2)
|
||||
return
|
||||
}
|
||||
fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
return
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
info, err := os.Stat(arg)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
base.SetExitStatus(1)
|
||||
continue
|
||||
}
|
||||
if info.IsDir() {
|
||||
scanDir(arg)
|
||||
} else {
|
||||
scanFile(arg, info, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// scanDir scans a directory for executables to run scanFile on.
|
||||
func scanDir(dir string) {
|
||||
filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
||||
if d.Type().IsRegular() || d.Type()&fs.ModeSymlink != 0 {
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
if *versionV {
|
||||
fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
scanFile(path, info, *versionV)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// isExe reports whether the file should be considered executable.
|
||||
func isExe(file string, info fs.FileInfo) bool {
|
||||
if runtime.GOOS == "windows" {
|
||||
return strings.HasSuffix(strings.ToLower(file), ".exe")
|
||||
}
|
||||
return info.Mode().IsRegular() && info.Mode()&0111 != 0
|
||||
}
|
||||
|
||||
// scanFile scans file to try to report the Go and module versions.
|
||||
// If mustPrint is true, scanFile will report any error reading file.
|
||||
// Otherwise (mustPrint is false, because scanFile is being called
|
||||
// by scanDir) scanFile prints nothing for non-Go executables.
|
||||
func scanFile(file string, info fs.FileInfo, mustPrint bool) {
|
||||
if info.Mode()&fs.ModeSymlink != 0 {
|
||||
// Accept file symlinks only.
|
||||
i, err := os.Stat(file)
|
||||
if err != nil || !i.Mode().IsRegular() {
|
||||
if mustPrint {
|
||||
fmt.Fprintf(os.Stderr, "%s: symlink\n", file)
|
||||
}
|
||||
return
|
||||
}
|
||||
info = i
|
||||
}
|
||||
|
||||
if !isExe(file, info) {
|
||||
if mustPrint {
|
||||
fmt.Fprintf(os.Stderr, "%s: not executable file\n", file)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
x, err := openExe(file)
|
||||
if err != nil {
|
||||
if mustPrint {
|
||||
fmt.Fprintf(os.Stderr, "%s: %v\n", file, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
defer x.Close()
|
||||
|
||||
vers, mod := findVers(x)
|
||||
if vers == "" {
|
||||
if mustPrint {
|
||||
fmt.Fprintf(os.Stderr, "%s: go version not found\n", file)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%s: %s\n", file, vers)
|
||||
if *versionM && mod != "" {
|
||||
fmt.Printf("\t%s\n", strings.ReplaceAll(mod[:len(mod)-1], "\n", "\n\t"))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// The build info blob left by the linker is identified by
|
||||
// a 16-byte header, consisting of buildInfoMagic (14 bytes),
|
||||
// the binary's pointer size (1 byte),
|
||||
// and whether the binary is big endian (1 byte).
|
||||
var buildInfoMagic = []byte("\xff Go buildinf:")
|
||||
|
||||
// findVers finds and returns the Go version and module version information
|
||||
// in the executable x.
|
||||
func findVers(x exe) (vers, mod string) {
|
||||
// Read the first 64kB of text to find the build info blob.
|
||||
text := x.DataStart()
|
||||
data, err := x.ReadData(text, 64*1024)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for ; !bytes.HasPrefix(data, buildInfoMagic); data = data[32:] {
|
||||
if len(data) < 32 {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the blob.
|
||||
ptrSize := int(data[14])
|
||||
bigEndian := data[15] != 0
|
||||
var bo binary.ByteOrder
|
||||
if bigEndian {
|
||||
bo = binary.BigEndian
|
||||
} else {
|
||||
bo = binary.LittleEndian
|
||||
}
|
||||
var readPtr func([]byte) uint64
|
||||
if ptrSize == 4 {
|
||||
readPtr = func(b []byte) uint64 { return uint64(bo.Uint32(b)) }
|
||||
} else {
|
||||
readPtr = bo.Uint64
|
||||
}
|
||||
vers = readString(x, ptrSize, readPtr, readPtr(data[16:]))
|
||||
if vers == "" {
|
||||
return
|
||||
}
|
||||
mod = readString(x, ptrSize, readPtr, readPtr(data[16+ptrSize:]))
|
||||
if len(mod) >= 33 && mod[len(mod)-17] == '\n' {
|
||||
// Strip module framing.
|
||||
mod = mod[16 : len(mod)-16]
|
||||
} else {
|
||||
mod = ""
|
||||
}
|
||||
return vers, mod
|
||||
}
|
||||
|
||||
// readString returns the string at address addr in the executable x.
|
||||
func readString(x exe, ptrSize int, readPtr func([]byte) uint64, addr uint64) string {
|
||||
hdr, err := x.ReadData(addr, uint64(2*ptrSize))
|
||||
if err != nil || len(hdr) < 2*ptrSize {
|
||||
return ""
|
||||
}
|
||||
dataAddr := readPtr(hdr)
|
||||
dataLen := readPtr(hdr[ptrSize:])
|
||||
data, err := x.ReadData(dataAddr, dataLen)
|
||||
if err != nil || uint64(len(data)) < dataLen {
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func TestDpkgMetadata_pURL(t *testing.T) {
|
||||
Version: "v",
|
||||
SourceVersion: "2.3",
|
||||
},
|
||||
expected: "pkg:deb/debian/p@v?upstream=s@2.3&distro=debian-11",
|
||||
expected: "pkg:deb/debian/p@v?upstream=s%402.3&distro=debian-11",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ package pkg
|
||||
|
||||
// GolangBinMetadata represents all captured data for a Golang Binary
|
||||
type GolangBinMetadata struct {
|
||||
GoCompiledVersion string `json:"goCompiledVersion" cyclonedx:"goCompiledVersion"`
|
||||
Architecture string `json:"architecture" cyclonedx:"architecture"`
|
||||
H1Digest string `json:"h1Digest" cyclonedx:"h1Digest"`
|
||||
BuildSettings map[string]string `json:"goBuildSettings,omitempty" cyclonedx:"goBuildSettings"`
|
||||
GoCompiledVersion string `json:"goCompiledVersion" cyclonedx:"goCompiledVersion"`
|
||||
Architecture string `json:"architecture" cyclonedx:"architecture"`
|
||||
H1Digest string `json:"h1Digest,omitempty" cyclonedx:"h1Digest"`
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNpmPackageJSONMetadata_PackageURL(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
metadata NpmPackageJSONMetadata
|
||||
expected string
|
||||
name string
|
||||
metadata NpmPackageJSONMetadata
|
||||
expected string
|
||||
namespace string
|
||||
}{
|
||||
{
|
||||
name: "no namespace",
|
||||
@@ -24,19 +27,36 @@ func TestNpmPackageJSONMetadata_PackageURL(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "split by namespace",
|
||||
metadata: NpmPackageJSONMetadata{
|
||||
Name: "npmcli/arborist",
|
||||
Version: "2.6.2",
|
||||
},
|
||||
expected: "pkg:npm/npmcli/arborist@2.6.2",
|
||||
namespace: "npmcli",
|
||||
},
|
||||
{
|
||||
name: "encoding @ symobl",
|
||||
metadata: NpmPackageJSONMetadata{
|
||||
Name: "@npmcli/arborist",
|
||||
Version: "2.6.2",
|
||||
},
|
||||
expected: "pkg:npm/@npmcli/arborist@2.6.2",
|
||||
expected: "pkg:npm/%40npmcli/arborist@2.6.2",
|
||||
namespace: "@npmcli",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
actual := tt.metadata.PackageURL(nil)
|
||||
assert.Equal(t, tt.expected, actual)
|
||||
_, err := packageurl.FromString(actual)
|
||||
decoded, err := packageurl.FromString(actual)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.namespace, decoded.Namespace)
|
||||
if decoded.Namespace != "" {
|
||||
assert.Equal(t, tt.metadata.Name, fmt.Sprintf("%s/%s", decoded.Namespace, decoded.Name))
|
||||
} else {
|
||||
assert.Equal(t, tt.metadata.Name, decoded.Name)
|
||||
}
|
||||
assert.Equal(t, tt.metadata.Version, decoded.Version)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestPythonPackageMetadata_pURL(t *testing.T) {
|
||||
CommitID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
},
|
||||
},
|
||||
expected: "pkg:pypi/name@v0.1.0?vcs_url=git+https:%2F%2Fgithub.com%2Ftest%2Ftest.git@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
expected: "pkg:pypi/name@v0.1.0?vcs_url=git+https://github.com/test/test.git%40aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
},
|
||||
{
|
||||
name: "should not respond to release info",
|
||||
|
||||
@@ -5,12 +5,10 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
)
|
||||
|
||||
const RpmDBGlob = "**/var/lib/rpm/Packages"
|
||||
@@ -24,7 +22,7 @@ var (
|
||||
type RpmdbMetadata struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Epoch *int `json:"epoch" cyclonedx:"epoch"`
|
||||
Epoch *int `json:"epoch" cyclonedx:"epoch" jsonschema:"nullable"`
|
||||
Arch string `json:"architecture"`
|
||||
Release string `json:"release" cyclonedx:"release"`
|
||||
SourceRpm string `json:"sourceRpm" cyclonedx:"sourceRpm"`
|
||||
|
||||
+6
-1
@@ -50,8 +50,13 @@ func URL(p Package, release *linux.Release) string {
|
||||
fields := re.Split(p.Name, -1)
|
||||
namespace = fields[0]
|
||||
name = strings.TrimPrefix(p.Name, namespace+"/")
|
||||
case p.Type == NpmPkg:
|
||||
fields := strings.SplitN(p.Name, "/", 2)
|
||||
if len(fields) > 1 {
|
||||
namespace = fields[0]
|
||||
name = fields[1]
|
||||
}
|
||||
}
|
||||
|
||||
// generate a purl from the package data
|
||||
return packageurl.NewPackageURL(
|
||||
purlType,
|
||||
|
||||
@@ -135,7 +135,7 @@ func (r *imageSquashResolver) RelativeFileByPath(_ Location, path string) *Locat
|
||||
return &paths[0]
|
||||
}
|
||||
|
||||
// FileContentsByLocation fetches file contents for a single file reference, irregardless of the source layer.
|
||||
// FileContentsByLocation fetches file contents for a single file reference, regardless of the source layer.
|
||||
// If the path does not exist an error is returned.
|
||||
func (r *imageSquashResolver) FileContentsByLocation(location Location) (io.ReadCloser, error) {
|
||||
entry, err := r.img.FileCatalog.Get(location.ref)
|
||||
|
||||
@@ -54,35 +54,38 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(string(test.formatOption), func(t *testing.T) {
|
||||
|
||||
originalSBOM, _ := catalogFixtureImage(t, "image-pkg-coverage")
|
||||
// use second image for relationships
|
||||
for _, image := range []string{"image-pkg-coverage", "image-owning-package"} {
|
||||
originalSBOM, _ := catalogFixtureImage(t, image)
|
||||
|
||||
format := syft.FormatByID(test.formatOption)
|
||||
require.NotNil(t, format)
|
||||
format := syft.FormatByID(test.formatOption)
|
||||
require.NotNil(t, format)
|
||||
|
||||
by1, err := syft.Encode(originalSBOM, format)
|
||||
assert.NoError(t, err)
|
||||
by1, err := syft.Encode(originalSBOM, format)
|
||||
assert.NoError(t, err)
|
||||
|
||||
newSBOM, newFormat, err := syft.Decode(bytes.NewReader(by1))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, format.ID(), newFormat.ID())
|
||||
newSBOM, newFormat, err := syft.Decode(bytes.NewReader(by1))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, format.ID(), newFormat.ID())
|
||||
|
||||
by2, err := syft.Encode(*newSBOM, format)
|
||||
assert.NoError(t, err)
|
||||
by2, err := syft.Encode(*newSBOM, format)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if test.redactor != nil {
|
||||
by1 = test.redactor(by1)
|
||||
by2 = test.redactor(by2)
|
||||
}
|
||||
if test.redactor != nil {
|
||||
by1 = test.redactor(by1)
|
||||
by2 = test.redactor(by2)
|
||||
}
|
||||
|
||||
if test.json {
|
||||
s1 := string(by1)
|
||||
s2 := string(by2)
|
||||
assert.JSONEq(t, s1, s2)
|
||||
} else {
|
||||
if !assert.True(t, bytes.Equal(by1, by2)) {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(string(by1), string(by2), true)
|
||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||
if test.json {
|
||||
s1 := string(by1)
|
||||
s2 := string(by2)
|
||||
assert.JSONEq(t, s1, s2)
|
||||
} else {
|
||||
if !assert.True(t, bytes.Equal(by1, by2)) {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(string(by1), string(by2), true)
|
||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
|
||||
func TestRegressionGoArchDiscovery(t *testing.T) {
|
||||
const (
|
||||
expectedELFPkg = 3
|
||||
expectedWINPkg = 3
|
||||
expectedMACOSPkg = 3
|
||||
expectedELFPkg = 4
|
||||
expectedWINPkg = 4
|
||||
expectedMACOSPkg = 4
|
||||
)
|
||||
// This is a regression test to make sure the way we detect go binary packages
|
||||
// stays consistent and reproducible as the tool chain evolves
|
||||
|
||||
Reference in New Issue
Block a user