mirror of
https://github.com/anchore/grype.git
synced 2026-10-28 08:24:36 +08:00
chore: replace the integration tests with the quality gate (#3852)
* chore: replace the integration tests with the quality gate - the Go integration tests in `test/integration` are gone, and the quality gate moves from `test/quality` into its place - tasks are now `make integration`, `integration:score`, `integration:update-db` and `integration:clean`, matching vunnel's `integration:` tasks - the race detector scan that used to ride along with the integration tests is now its own `make smoke-test` task and "Smoke tests" CI job - labels live in `test/integration/additional-claims`, and the gate reads vunnel's from `tests/integration/additional-claims` (anchore/vunnel#1418) Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * test: check that each SBOM format matches the same as an image scan - `make integration:sbom-formats` scans a few of the quality gate's images with grype from this checkout, then scans an SBOM of each image in syft-json, spdx-json and spdx-tag-value, and fails when the matches differ - it uses the DB pinned in `test/integration/gates/pr.yaml`, so the comparison holds still between runs - a format quirk that changes matches for a known reason is listed against that image and format, and a failure logs how the packages behind the differing matches differ - runs as the new "Integration tests (SBOM formats)" CI job, in parallel with the gate Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * chore: split the integration tests into quality and api suites - `make integration` runs both suites: `integration:quality` (the yardstick gate) and `integration:api` (the Go tests against grype's library) - `integration:score` is now `integration:quality:score` - CI runs the suites as a matrix in parallel, and one "Integration tests" check requires both Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * chore: log yardstick progress in CI yardstick only shows progress on a terminal, so the CI job printed nothing until the verdict. In CI (`CI=true`) it now runs with `-v`. Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
1 parent
1c10431d08
commit
7c68081d9c
73 files changed
+361
-15419
No files matched your search
+1
-16
@@ -4,22 +4,7 @@ cooldown: 7d
|
||||
# need to specify tools here that are not already defined there (or that we want to override
|
||||
# with different versions).
|
||||
tools:
|
||||
# used for integration tests
|
||||
- name: skopeo
|
||||
version:
|
||||
want: v1.24.1
|
||||
method: go-install
|
||||
with:
|
||||
module: github.com/containers/skopeo
|
||||
entrypoint: cmd/skopeo
|
||||
args:
|
||||
- "-tags"
|
||||
- containers_image_openpgp
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
- GO_DYN_FLAGS=""
|
||||
|
||||
# used in the quality gate to compare grype from this checkout with the latest release
|
||||
# used in the integration tests (quality gate) to compare grype from this checkout with the latest release
|
||||
- name: yardstick
|
||||
version:
|
||||
want: v0.17.0
|
||||
|
||||
@@ -3,4 +3,3 @@
|
||||
|
||||
# fixtures that must keep their crlf line endings byte for byte
|
||||
grype/distro/testdata/unprintable -text
|
||||
test/integration/testdata/image-alpine-match-coverage/etc/os-release -text
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
# these are checks that should be run on pull-request and merges to main.
|
||||
# we do NOT want to kick off a release if these have not been verified on main.
|
||||
# Please see the validations.yaml workflow for the names that should be used here.
|
||||
checks: '["Acceptance tests (Linux)", "Acceptance tests (Mac)", "Build snapshot artifacts", "CLI tests (Linux)", "Containers-storage tests (Buildah)", "Containers-storage tests (Podman)", "Integration tests", "Quality tests", "Static analysis", "Unit tests"]'
|
||||
checks: '["Acceptance tests (Linux)", "Acceptance tests (Mac)", "Build snapshot artifacts", "CLI tests (Linux)", "Containers-storage tests (Buildah)", "Containers-storage tests (Podman)", "Integration tests", "Smoke tests", "Static analysis", "Unit tests"]'
|
||||
|
||||
# only release core assets within the "release" job. Any other assets not already under the purview of the
|
||||
# goreleaser configuration should be added as separate jobs to allow for debugging separately from the release workflow
|
||||
|
||||
@@ -82,12 +82,35 @@ jobs:
|
||||
- name: Run unit tests
|
||||
run: make unit
|
||||
|
||||
Quality-Test:
|
||||
Integration-Test:
|
||||
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
|
||||
name: "Quality tests"
|
||||
name: "Integration tests"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [Integration-Test-Suite]
|
||||
# a skipped job satisfies a required check, so this job must always run and fail explicitly
|
||||
# unless every dependency succeeded (otherwise a failing PR can still be auto-merged)
|
||||
if: ${{ always() }}
|
||||
permissions: {}
|
||||
steps:
|
||||
- name: Require every integration suite to succeed
|
||||
env:
|
||||
NEEDS: ${{ toJSON(needs) }}
|
||||
run: |
|
||||
echo "$NEEDS" | jq -e 'length > 0 and all(.[]; .result == "success")' > /dev/null || {
|
||||
echo "$NEEDS" | jq -r 'to_entries[] | "\(.key): \(.value.result)"'
|
||||
exit 1
|
||||
}
|
||||
echo All integration suites passed!
|
||||
|
||||
Integration-Test-Suite:
|
||||
name: "Integration tests (${{ matrix.suite }})"
|
||||
runs-on: ubuntu-22.04-4core-16gb
|
||||
permissions:
|
||||
contents: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
suite: [quality, api]
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
@@ -95,28 +118,27 @@ jobs:
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: $/.github/actions/bootstrap
|
||||
with:
|
||||
cache-test-fixtures: true
|
||||
|
||||
- name: Run quality tests
|
||||
run: make quality
|
||||
- name: Run the ${{ matrix.suite }} suite
|
||||
run: make "integration:$SUITE"
|
||||
env:
|
||||
SUITE: ${{ matrix.suite }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Archive the gate state
|
||||
if: ${{ failure() }}
|
||||
if: ${{ failure() && matrix.suite == 'quality' }}
|
||||
# a run that fails before scanning leaves no .yardstick/runs; archive the gates anyway
|
||||
run: tar -czvf qg-capture-state.tar.gz --ignore-failed-read -C test/quality .yardstick.yaml gates .yardstick/runs
|
||||
run: tar -czvf qg-capture-state.tar.gz --ignore-failed-read -C test/integration .yardstick.yaml gates .yardstick/runs
|
||||
|
||||
- name: Upload the gate state archive
|
||||
if: ${{ failure() }}
|
||||
if: ${{ failure() && matrix.suite == 'quality' }}
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: qg-capture-state
|
||||
path: qg-capture-state.tar.gz
|
||||
|
||||
- name: Show instructions to debug
|
||||
if: ${{ failure() }}
|
||||
if: ${{ failure() && matrix.suite == 'quality' }}
|
||||
run: |
|
||||
ARCHIVE_BASENAME=qg-capture-state
|
||||
ARCHIVE_NAME=$ARCHIVE_BASENAME.zip
|
||||
@@ -128,23 +150,22 @@ jobs:
|
||||
|
||||
It holds the gate files and their scans, which re-score without the DB or new scans:
|
||||
\`\`\`bash
|
||||
# copy the archive to the test/quality directory
|
||||
cd test/quality
|
||||
# copy the archive to the test/integration directory
|
||||
cd test/integration
|
||||
unzip $ARCHIVE_NAME && tar -xzf $ARCHIVE_BASENAME.tar.gz
|
||||
make -C ../.. quality:score
|
||||
make -C ../.. integration:quality:score
|
||||
\`\`\`
|
||||
|
||||
Now you can label what changed in the UI (it needs yardstick from the installer, since a \`go install\` build has no UI):
|
||||
\`\`\`bash
|
||||
yardstick claims serve gates/pr.yaml --open
|
||||
make -C ../.. quality:score
|
||||
make -C ../.. integration:quality:score
|
||||
\`\`\`
|
||||
EOF
|
||||
|
||||
|
||||
Integration-Test:
|
||||
Smoke-Test:
|
||||
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
|
||||
name: "Integration tests"
|
||||
name: "Smoke tests"
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -155,17 +176,9 @@ jobs:
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: $/.github/actions/bootstrap
|
||||
with:
|
||||
cache-test-fixtures: true
|
||||
|
||||
- name: Restore integration test cache
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 #v6.1.0
|
||||
with:
|
||||
path: ${{ github.workspace }}/test/integration/testdata/cache
|
||||
key: ${{ runner.os }}-integration-test-cache-${{ hashFiles('test/integration/testdata/cache.fingerprint') }}
|
||||
|
||||
- name: Run integration tests
|
||||
run: make integration
|
||||
- name: Run smoke tests
|
||||
run: make smoke-test
|
||||
|
||||
Build-Snapshot-Artifacts:
|
||||
name: "Build snapshot artifacts"
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
. "github.com/anchore/go-make"
|
||||
"github.com/anchore/go-make/config"
|
||||
"github.com/anchore/go-make/file"
|
||||
"github.com/anchore/go-make/lang"
|
||||
"github.com/anchore/go-make/run"
|
||||
)
|
||||
|
||||
const integrationDir = "test/integration"
|
||||
|
||||
// integrationDBRef matches the pinned DB in a gate file's setups: the archive URL and its checksum
|
||||
var integrationDBRef = regexp.MustCompile(`https://grype\.anchore\.io/databases/v6/[^"@]+@sha256:[0-9a-f]{64}`)
|
||||
|
||||
// integrationTasks run the two integration suites, both on the DB pinned in test/integration/gates:
|
||||
// - quality: grype built from this checkout against the latest grype release, scored against the labels in
|
||||
// anchore/claims. yardstick is installed from .binny.yaml on first use, and downloads and caches the DB itself.
|
||||
// - api: the Go tests in test/integration, run against grype's library from this checkout.
|
||||
func integrationTasks() Task {
|
||||
return Task{
|
||||
Tasks: []Task{
|
||||
{
|
||||
Name: "integration",
|
||||
Description: "run every integration suite",
|
||||
Dependencies: Deps("integration:quality", "integration:api"),
|
||||
},
|
||||
{
|
||||
Name: "integration:quality",
|
||||
Description: "run the quality gate (build grype, scan with it and the latest release, score against labels)",
|
||||
Run: func() {
|
||||
// built like the release (see .goreleaser.yaml), so the candidate differs from the reference only in code
|
||||
Run("go build -tags "+buildTags+" -o "+integrationDir+"/bin/grype ./cmd/grype", run.Env("CGO_ENABLED", "0"))
|
||||
runIntegrationGates()
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "integration:api",
|
||||
Description: "run the Go integration tests against grype's library",
|
||||
Run: func() {
|
||||
Run(`go test -v -tags=` + buildTags + ` ./` + integrationDir)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "integration:quality:score",
|
||||
Description: "re-score the last quality gate scans against the current labels, without scanning",
|
||||
Run: func() {
|
||||
runIntegrationGates("score")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "integration:update-db",
|
||||
Description: "pin both integration suites to the latest published DB",
|
||||
Run: func() {
|
||||
var listing []struct {
|
||||
Path string `json:"path"`
|
||||
Checksum string `json:"checksum"`
|
||||
}
|
||||
lang.Throw(json.Unmarshal([]byte(Run("go run ./cmd/grype db list -o json", run.Quiet())), &listing))
|
||||
ref := "https://grype.anchore.io/databases/v6/" + listing[0].Path + "@" + listing[0].Checksum
|
||||
for _, gate := range file.FindAll(integrationDir + "/gates/*.yaml") {
|
||||
file.Write(gate, integrationDBRef.ReplaceAllString(file.Read(gate), ref))
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "integration:clean",
|
||||
Description: "remove the integration suites' grype build, scans and DB",
|
||||
RunsOn: lang.List("clean"),
|
||||
Run: func() {
|
||||
file.Delete(integrationDir + "/bin")
|
||||
file.Delete(integrationDir + "/.yardstick")
|
||||
file.Delete(integrationDir + "/.cache")
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// runIntegrationGates runs yardstick over every gate file, in test/integration so its .yardstick.yaml applies. Only
|
||||
// yardstick runs there: Run installs it with binny first, which must run from the repo root to find .binny.yaml.
|
||||
// The verdict is on stdout, which Run would otherwise only capture.
|
||||
func runIntegrationGates(args ...string) {
|
||||
// yardstick shows progress only on a terminal, so without logs a CI run is silent until the verdict
|
||||
if config.CI {
|
||||
args = append(args, "-v")
|
||||
}
|
||||
for _, gate := range file.FindAll(integrationDir + "/gates/*.yaml") {
|
||||
args = append(args, strings.TrimPrefix(gate, integrationDir+"/"))
|
||||
}
|
||||
Run("yardstick", run.Args(args...), run.InDir(integrationDir), run.Stdout(os.Stdout))
|
||||
}
|
||||
+8
-14
@@ -41,10 +41,10 @@ func main() {
|
||||
goreleaser.Tasks(),
|
||||
|
||||
buildTask(),
|
||||
integrationTask(),
|
||||
smokeTestTask(),
|
||||
cliTask(),
|
||||
containersStorageTestTask(),
|
||||
qualityTasks(),
|
||||
integrationTasks(),
|
||||
|
||||
generateTask(),
|
||||
updateOSVModelTask(),
|
||||
@@ -87,19 +87,14 @@ func buildTask() Task {
|
||||
}
|
||||
}
|
||||
|
||||
// integrationTask runs the integration test suite plus a quick race-detector
|
||||
// smoke test of the CLI against alpine:latest.
|
||||
func integrationTask() Task {
|
||||
// smokeTestTask scans alpine:latest with the data race detector on, exercising most of the CLI end to end.
|
||||
func smokeTestTask() Task {
|
||||
return Task{
|
||||
Name: "integration",
|
||||
Description: "run integration tests",
|
||||
RunsOn: lang.List("test"),
|
||||
Name: "smoke-test",
|
||||
Description: "scan an image with the race detector enabled",
|
||||
Run: func() {
|
||||
Run(`go test -v -tags=` + buildTags + ` ./test/integration`)
|
||||
// update database outside race detector, since doing so with
|
||||
// race detector on is very slow
|
||||
// update the DB outside the race detector, which makes it very slow
|
||||
Run(fmt.Sprintf(`go run ./cmd/%s db update`, project))
|
||||
// exercise most of the CLI with the data race detector enabled
|
||||
Run(fmt.Sprintf(`go run -race -tags=%s ./cmd/%s alpine:latest`, buildTags, project))
|
||||
},
|
||||
}
|
||||
@@ -336,7 +331,7 @@ func installTestTasks() Task {
|
||||
}
|
||||
}
|
||||
|
||||
// fingerprintsTask regenerates cache.fingerprint files for the three test
|
||||
// fingerprintsTask regenerates cache.fingerprint files for the test
|
||||
// suites that participate in CI caching. Not auto-discovered by
|
||||
// gotest.FixtureTasks because test/install/Makefile lives outside the
|
||||
// testdata/test-fixtures convention.
|
||||
@@ -346,7 +341,6 @@ func fingerprintsTask() Task {
|
||||
Description: "generate test fixture cache fingerprints",
|
||||
Run: func() {
|
||||
for _, dir := range []string{
|
||||
"test/integration/testdata",
|
||||
"test/install",
|
||||
"test/cli/testdata",
|
||||
} {
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
. "github.com/anchore/go-make"
|
||||
"github.com/anchore/go-make/file"
|
||||
"github.com/anchore/go-make/lang"
|
||||
"github.com/anchore/go-make/run"
|
||||
)
|
||||
|
||||
const qualityDir = "test/quality"
|
||||
|
||||
// qualityDBRef matches the pinned DB in a gate file's setups: the archive URL and its checksum
|
||||
var qualityDBRef = regexp.MustCompile(`https://grype\.anchore\.io/databases/v6/[^"@]+@sha256:[0-9a-f]{64}`)
|
||||
|
||||
// qualityTasks run the quality gate: grype built from this checkout against the latest grype release, both on
|
||||
// the DB pinned in test/quality/gates, scored against the labels in anchore/claims. yardstick is installed from
|
||||
// .binny.yaml on first use, and downloads and caches the DB itself.
|
||||
func qualityTasks() Task {
|
||||
return Task{
|
||||
Tasks: []Task{
|
||||
{
|
||||
Name: "quality",
|
||||
Description: "run the quality gate (build grype, scan with it and the latest release, score against labels)",
|
||||
Run: func() {
|
||||
// built like the release (see .goreleaser.yaml), so the candidate differs from the reference only in code
|
||||
Run("go build -tags "+buildTags+" -o "+qualityDir+"/bin/grype ./cmd/grype", run.Env("CGO_ENABLED", "0"))
|
||||
runQualityGates()
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "quality:score",
|
||||
Description: "re-score the last quality gate scans against the current labels, without scanning",
|
||||
Run: func() {
|
||||
runQualityGates("score")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "update-quality-gate-db",
|
||||
Description: "pin the quality gate to the latest published DB",
|
||||
Run: func() {
|
||||
var listing []struct {
|
||||
Path string `json:"path"`
|
||||
Checksum string `json:"checksum"`
|
||||
}
|
||||
lang.Throw(json.Unmarshal([]byte(Run("go run ./cmd/grype db list -o json", run.Quiet())), &listing))
|
||||
ref := "https://grype.anchore.io/databases/v6/" + listing[0].Path + "@" + listing[0].Checksum
|
||||
for _, gate := range file.FindAll(qualityDir + "/gates/*.yaml") {
|
||||
file.Write(gate, qualityDBRef.ReplaceAllString(file.Read(gate), ref))
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "clean:quality",
|
||||
Description: "remove the quality gate's grype build and scans",
|
||||
RunsOn: lang.List("clean"),
|
||||
Run: func() {
|
||||
file.Delete(qualityDir + "/bin")
|
||||
file.Delete(qualityDir + "/.yardstick")
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// runQualityGates runs yardstick over every gate file, in test/quality so its .yardstick.yaml applies. Only
|
||||
// yardstick runs there: Run installs it with binny first, which must run from the repo root to find .binny.yaml.
|
||||
// The verdict is on stdout, which Run would otherwise only capture.
|
||||
func runQualityGates(args ...string) {
|
||||
for _, gate := range file.FindAll(qualityDir + "/gates/*.yaml") {
|
||||
args = append(args, strings.TrimPrefix(gate, qualityDir+"/"))
|
||||
}
|
||||
Run("yardstick", run.Args(args...), run.InDir(qualityDir), run.Stdout(os.Stdout))
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
bin/
|
||||
.yardstick/
|
||||
.cache/
|
||||
File renamed without changes.
@@ -2,5 +2,5 @@
|
||||
# source wins over the same label in an earlier one. New labels are written to the last, ./additional-claims.
|
||||
claims:
|
||||
- github.com/anchore/claims@main
|
||||
- github.com/anchore/vunnel/tests/quality/additional-claims@main
|
||||
- github.com/anchore/vunnel/tests/integration/additional-claims@main
|
||||
- ./additional-claims
|
||||
@@ -1,10 +1,10 @@
|
||||
# Match quality testing
|
||||
# Integration tests
|
||||
|
||||
The quality gate checks that a grype change does not make matching worse. It scans a fixed set of SBOMs with grype built from this checkout and with the latest grype release, both on the same pinned DB, and scores both scans against labels with [yardstick](https://github.com/anchore/yardstick).
|
||||
The integration tests are two suites, both on the DB pinned in `gates/pr.yaml`: the quality suite and the API suite (see below). The quality suite is a gate that checks a grype change does not make matching worse. It scans a fixed set of SBOMs with grype built from this checkout and with the latest grype release, both on the same pinned DB, and scores both scans against labels with [yardstick](https://github.com/anchore/yardstick).
|
||||
|
||||
- `gates/*.yaml` are the gates: the images, the two grype setups and the checks. Each gate keeps vulnerabilities up to one year (`vulnerabilities.maxYear`).
|
||||
- Labels and SBOMs come from [anchore/claims](https://github.com/anchore/claims), plus the labels in vunnel's `tests/quality/additional-claims` and in `additional-claims/` here, all named in `.yardstick.yaml`.
|
||||
- Each gate pins the DB both setups import, by URL and checksum; yardstick downloads and caches it. `make update-quality-gate-db` moves every gate to the latest published DB.
|
||||
- Labels and SBOMs come from [anchore/claims](https://github.com/anchore/claims), plus the labels in vunnel's `tests/integration/additional-claims` and in `additional-claims/` here, all named in `.yardstick.yaml`.
|
||||
- Each gate pins the DB both setups import, by URL and checksum; yardstick downloads and caches it. `make integration:update-db` moves every gate to the latest published DB.
|
||||
- `.grype.yaml` is the grype config both setups run with (CPE matching on for every ecosystem, `by-cve`).
|
||||
- yardstick is pinned in the repo's `.binny.yaml` and installed into `.tool/` the first time a task runs it.
|
||||
|
||||
@@ -13,10 +13,16 @@ The quality gate checks that a grype change does not make matching worse. It sca
|
||||
From the repo root:
|
||||
|
||||
```
|
||||
make quality # build grype, get SBOMs, scan with both setups and score; exits 1 when a gate fails
|
||||
make quality:score # re-score the last scans against the current labels, without scanning
|
||||
make integration # run both suites
|
||||
make integration:quality # build grype, get SBOMs, scan with both setups and score; exits 1 when a gate fails
|
||||
make integration:quality:score # re-score the last scans against the current labels, without scanning
|
||||
make integration:api # run the Go tests against grype's library
|
||||
```
|
||||
|
||||
## API suite
|
||||
|
||||
The Go tests here run against grype's library from this checkout, separate from the gate. `sbom_formats_test.go` scans a few of the gate's images, then scans an SBOM of each image in every format grype reads, and fails when the matches differ. It uses the DB pinned in `gates/pr.yaml`, imported into `.cache/` on first run. A format that cannot carry something the image scan used (file ownership, say) changes matches for a known reason; list those matches in the image's `knownFormatLoss` for that format. A failure logs how the packages behind the differing matches differ, which is usually that reason.
|
||||
|
||||
## What is the quality gate criteria
|
||||
|
||||
Each gate's checks are evaluated per image:
|
||||
@@ -48,20 +54,20 @@ Vulnerability matching has two inputs, the packages found in the scanned artifac
|
||||
|
||||
## Workflow
|
||||
|
||||
When the gate fails, `make quality` prints what changed between the two setups, grouped by cause, with the labels each change hits and what labeling the unlabeled ones would do to the verdict. Some failures are real regressions, and some only need labels.
|
||||
When the gate fails, `make integration:quality` prints what changed between the two setups, grouped by cause, with the labels each change hits and what labeling the unlabeled ones would do to the verdict. Some failures are real regressions, and some only need labels.
|
||||
|
||||
To label, use the yardstick label UI (`make quality` installs yardstick in `.tool/`):
|
||||
To label, use the yardstick label UI (`make integration:quality` installs yardstick in `.tool/`):
|
||||
|
||||
```
|
||||
../../.tool/yardstick claims serve gates/pr.yaml --open
|
||||
make -C ../.. quality:score # re-score with the new labels, no new scans
|
||||
make -C ../.. integration:quality:score # re-score with the new labels, no new scans
|
||||
```
|
||||
|
||||
A failed CI run uploads a `qg-capture-state` artifact holding the gate files, their scans and `.yardstick.yaml`, and the job summary says how to use it. Extracted into `test/quality`, it re-scores and labels as above with no DB, no grype and no new scans:
|
||||
A failed CI run uploads a `qg-capture-state` artifact holding the gate files, their scans and `.yardstick.yaml`, and the job summary says how to use it. Extracted into `test/integration`, it re-scores and labels as above with no DB, no grype and no new scans:
|
||||
|
||||
```
|
||||
unzip qg-capture-state.zip && tar -xzf qg-capture-state.tar.gz
|
||||
make -C ../.. quality:score
|
||||
make -C ../.. integration:quality:score
|
||||
```
|
||||
|
||||
New labels are written to `additional-claims/`, which the gate reads after anchore/claims and vunnel's `tests/quality/additional-claims`. Commit them there, or move labels that are generally useful to [anchore/claims](https://github.com/anchore/claims) with a pull request; the gate reads its `main` branch.
|
||||
New labels are written to `additional-claims/`, which the gate reads after anchore/claims and vunnel's `tests/integration/additional-claims`. Commit them there, or move labels that are generally useful to [anchore/claims](https://github.com/anchore/claims) with a pull request; the gate reads its `main` branch.
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
|
||||
Match labels that belong with grype's quality gate rather than in [anchore/claims](https://github.com/anchore/claims). yardstick reads this directory after anchore/claims, so a label here wins over the same label there, and `yardstick claims serve` writes new labels here.
|
||||
|
||||
Labels that are generally useful should move to anchore/claims with a pull request there. vunnel's quality gate also reads this directory from grype's `main` branch, so it has to stay in place even when it holds no labels.
|
||||
Labels that are generally useful should move to anchore/claims with a pull request there. vunnel's quality gate also reads this directory from grype's `main` branch (as `test/integration/additional-claims`), so it has to stay in place even when it holds no labels.
|
||||
@@ -1,299 +0,0 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/grype/grype"
|
||||
"github.com/anchore/grype/grype/db/v6/distribution"
|
||||
"github.com/anchore/grype/grype/db/v6/installation"
|
||||
"github.com/anchore/grype/internal/log"
|
||||
"github.com/anchore/syft/syft/format/spdxjson"
|
||||
"github.com/anchore/syft/syft/format/spdxtagvalue"
|
||||
"github.com/anchore/syft/syft/format/syftjson"
|
||||
syftPkg "github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func getLatestURL() string {
|
||||
if value, ok := os.LookupEnv("GRYPE_DB_UPDATE_URL"); ok {
|
||||
return value
|
||||
}
|
||||
return distribution.DefaultConfig().LatestURL
|
||||
}
|
||||
|
||||
func must(e sbom.FormatEncoder, err error) sbom.FormatEncoder {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func TestCompareSBOMInputToLibResults(t *testing.T) {
|
||||
// get a grype DB
|
||||
store, status, err := grype.LoadVulnerabilityDB(distribution.Config{
|
||||
LatestURL: getLatestURL(),
|
||||
}, installation.Config{
|
||||
DBRootDir: "testdata/grype-db",
|
||||
ValidateChecksum: false,
|
||||
}, true)
|
||||
assert.NoError(t, err)
|
||||
defer log.CloseAndLogError(store, status.Path)
|
||||
|
||||
definedPkgTypes := strset.New()
|
||||
for _, p := range syftPkg.AllPkgs {
|
||||
definedPkgTypes.Add(string(p))
|
||||
}
|
||||
// exceptions: rust, php, dart, msrc (kb), etc. are not under test
|
||||
definedPkgTypes.Remove(
|
||||
string(syftPkg.BinaryPkg), // these are removed due to overlap-by-file-ownership
|
||||
string(syftPkg.BitnamiPkg),
|
||||
string(syftPkg.PhpPeclPkg),
|
||||
string(syftPkg.PhpPearPkg),
|
||||
string(syftPkg.RustPkg),
|
||||
string(syftPkg.KbPkg),
|
||||
string(syftPkg.DartPubPkg),
|
||||
string(syftPkg.DotnetPkg),
|
||||
string(syftPkg.PhpComposerPkg),
|
||||
string(syftPkg.ConanPkg),
|
||||
string(syftPkg.CondaPkg),
|
||||
string(syftPkg.HexPkg),
|
||||
string(syftPkg.PortagePkg),
|
||||
string(syftPkg.HomebrewPkg),
|
||||
string(syftPkg.CocoapodsPkg),
|
||||
string(syftPkg.HackagePkg),
|
||||
string(syftPkg.NixPkg),
|
||||
string(syftPkg.JenkinsPluginPkg), // package type cannot be inferred for all formats
|
||||
string(syftPkg.LinuxKernelPkg),
|
||||
string(syftPkg.LinuxKernelModulePkg),
|
||||
string(syftPkg.ModelPkg),
|
||||
string(syftPkg.OpamPkg),
|
||||
string(syftPkg.Rpkg),
|
||||
string(syftPkg.SwiplPackPkg),
|
||||
string(syftPkg.SwiftPkg),
|
||||
string(syftPkg.GithubActionPkg),
|
||||
string(syftPkg.GithubActionWorkflowPkg),
|
||||
string(syftPkg.GraalVMNativeImagePkg),
|
||||
string(syftPkg.ErlangOTPPkg),
|
||||
string(syftPkg.WordpressPluginPkg), // TODO: remove me when there is a matcher for this merged in https://github.com/anchore/grype/pull/1553
|
||||
string(syftPkg.LuaRocksPkg),
|
||||
string(syftPkg.TerraformPkg),
|
||||
string(syftPkg.AppleAppBundlePkg), // macOS .app bundles; no matcher and not present in the test images
|
||||
string(syftPkg.VcpkgPkg),
|
||||
string(syftPkg.CpanPkg), // no matcher and not present in the test images
|
||||
)
|
||||
observedPkgTypes := strset.New()
|
||||
testCases := []struct {
|
||||
name string
|
||||
image string
|
||||
format sbom.FormatEncoder
|
||||
// knownFormatLossMatches lists match keys (vuln-pkg-version) that are expected to
|
||||
// appear only in results from this SBOM format (and not from an image scan) due to
|
||||
// metadata loss during format encoding. For example, SPDX does not preserve APK file
|
||||
// ownership metadata, so distro-package-fixed ignore rules cannot be scoped to owned
|
||||
// paths and are not emitted — causing matches that the image scan correctly suppresses
|
||||
// to remain visible. This does NOT apply to syft-json, which preserves all metadata.
|
||||
knownFormatLossMatches []string
|
||||
}{
|
||||
{
|
||||
image: "anchore/test_images:vulnerabilities-alpine",
|
||||
format: syftjson.NewFormatEncoder(),
|
||||
name: "alpine-syft-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:vulnerabilities-alpine",
|
||||
format: must(spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig())),
|
||||
name: "alpine-spdx-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:vulnerabilities-alpine",
|
||||
format: must(spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.DefaultEncoderConfig())),
|
||||
name: "alpine-spdx-tag-value",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:gems",
|
||||
format: syftjson.NewFormatEncoder(),
|
||||
name: "gems-syft-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:gems",
|
||||
format: must(spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig())),
|
||||
name: "gems-spdx-json",
|
||||
// SPDX does not preserve APK file ownership metadata, so distro-package-fixed
|
||||
// ignore rules cannot be scoped to owned paths and are not emitted from the SBOM.
|
||||
knownFormatLossMatches: []string{"GHSA-8cr8-4vfw-mr7h-rexml-3.2.3.1"},
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:gems",
|
||||
format: must(spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.DefaultEncoderConfig())),
|
||||
name: "gems-spdx-tag-value",
|
||||
// SPDX does not preserve APK file ownership metadata, so distro-package-fixed
|
||||
// ignore rules cannot be scoped to owned paths and are not emitted from the SBOM.
|
||||
knownFormatLossMatches: []string{"GHSA-8cr8-4vfw-mr7h-rexml-3.2.3.1"},
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:vulnerabilities-debian",
|
||||
format: syftjson.NewFormatEncoder(),
|
||||
name: "debian-syft-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:vulnerabilities-debian",
|
||||
format: must(spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig())),
|
||||
name: "debian-spdx-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:vulnerabilities-debian",
|
||||
format: must(spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.DefaultEncoderConfig())),
|
||||
name: "debian-spdx-tag-value",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:vulnerabilities-centos",
|
||||
format: syftjson.NewFormatEncoder(),
|
||||
name: "centos-syft-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:vulnerabilities-centos",
|
||||
format: must(spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig())),
|
||||
name: "centos-spdx-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:vulnerabilities-centos",
|
||||
format: must(spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.DefaultEncoderConfig())),
|
||||
name: "centos-spdx-tag-value",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:npm",
|
||||
format: syftjson.NewFormatEncoder(),
|
||||
name: "npm-syft-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:npm",
|
||||
format: must(spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig())),
|
||||
name: "npm-spdx-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:npm",
|
||||
format: must(spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.DefaultEncoderConfig())),
|
||||
name: "npm-spdx-tag-value",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:java",
|
||||
format: syftjson.NewFormatEncoder(),
|
||||
name: "java-syft-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:java",
|
||||
format: must(spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig())),
|
||||
name: "java-spdx-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:java",
|
||||
format: must(spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.DefaultEncoderConfig())),
|
||||
name: "java-spdx-tag-value",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:golang-56d52bc",
|
||||
format: syftjson.NewFormatEncoder(),
|
||||
name: "go-syft-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:golang-56d52bc",
|
||||
format: must(spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig())),
|
||||
name: "go-spdx-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:golang-56d52bc",
|
||||
format: must(spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.DefaultEncoderConfig())),
|
||||
name: "go-spdx-tag-value",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:arch",
|
||||
format: syftjson.NewFormatEncoder(),
|
||||
name: "arch-syft-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:arch",
|
||||
format: must(spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig())),
|
||||
name: "arch-spdx-json",
|
||||
},
|
||||
|
||||
{
|
||||
image: "anchore/test_images:arch",
|
||||
format: must(spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.DefaultEncoderConfig())),
|
||||
name: "arch-spdx-tag-value",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
imageArchive := PullThroughImageCache(t, tc.image)
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// get SBOM from syft, write to temp file
|
||||
sbomBytes := getSyftSBOM(t, imageArchive, "docker-archive", tc.format)
|
||||
sbomFile, err := os.CreateTemp("", "")
|
||||
assert.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
assert.NoError(t, os.Remove(sbomFile.Name()))
|
||||
})
|
||||
_, err = sbomFile.WriteString(sbomBytes)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, sbomFile.Close())
|
||||
|
||||
// get vulns (sbom)
|
||||
matchesFromSbom, _, pkgsFromSbom, err := grype.FindVulnerabilities(store, fmt.Sprintf("sbom:%s", sbomFile.Name()), source.SquashedScope, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// get vulns (image)
|
||||
imageSource := fmt.Sprintf("docker-archive:%s", imageArchive)
|
||||
matchesFromImage, _, _, err := grype.FindVulnerabilities(store, imageSource, source.SquashedScope, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// compare packages (shallow)
|
||||
matchSetFromSbom := getMatchSet(matchesFromSbom)
|
||||
matchSetFromImage := getMatchSet(matchesFromImage)
|
||||
|
||||
sbomOnly := strset.Difference(matchSetFromSbom, matchSetFromImage)
|
||||
if len(tc.knownFormatLossMatches) > 0 {
|
||||
sbomOnly.Remove(tc.knownFormatLossMatches...)
|
||||
}
|
||||
assert.Empty(t, sbomOnly.List(), "vulnerabilities present only in results when using sbom as input")
|
||||
assert.Empty(t, strset.Difference(matchSetFromImage, matchSetFromSbom).List(), "vulnerabilities present only in results when using image as input")
|
||||
|
||||
// track all covered package types (for use after the test)
|
||||
for _, p := range pkgsFromSbom {
|
||||
observedPkgTypes.Add(string(p.Type))
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// ensure we've covered all package types (-rust, -kb)
|
||||
unobservedPackageTypes := strset.Difference(definedPkgTypes, observedPkgTypes)
|
||||
assert.Empty(t, unobservedPackageTypes.List(), "not all package type were covered in testing")
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"github.com/anchore/grype/grype/version"
|
||||
"github.com/anchore/grype/grype/vulnerability"
|
||||
"github.com/anchore/grype/grype/vulnerability/mock"
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
)
|
||||
|
||||
func newMockDbProvider() vulnerability.Provider {
|
||||
return mock.VulnerabilityProvider([]vulnerability.Vulnerability{
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-jdk",
|
||||
Namespace: "nvd:cpe",
|
||||
},
|
||||
PackageName: "jdk",
|
||||
Constraint: version.MustGetConstraint("< 1.8.0_401", version.JVMFormat),
|
||||
CPEs: []cpe.CPE{cpe.Must("cpe:2.3:a:oracle:jdk:*:*:*:*:*:*:*:*", "")},
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-2024-0000",
|
||||
Namespace: "nvd:cpe",
|
||||
},
|
||||
PackageName: "libvncserver",
|
||||
Constraint: version.MustGetConstraint("< 0.9.10", version.UnknownFormat),
|
||||
CPEs: []cpe.CPE{cpe.Must("cpe:2.3:a:lib_vnc_project-(server):libvncserver:*:*:*:*:*:*:*:*", "")},
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-bogus-my-package-1",
|
||||
Namespace: "nvd:cpe",
|
||||
},
|
||||
PackageName: "my-package",
|
||||
Constraint: version.MustGetConstraint("< 2.0", version.UnknownFormat),
|
||||
CPEs: []cpe.CPE{cpe.Must("cpe:2.3:a:bogus:my-package:*:*:*:*:*:*:something:*", "")},
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-bogus-my-package-2-never-match",
|
||||
Namespace: "nvd:cpe",
|
||||
},
|
||||
PackageName: "my-package",
|
||||
Constraint: version.MustGetConstraint("< 2.0", version.UnknownFormat),
|
||||
CPEs: []cpe.CPE{cpe.Must("cpe:2.3:a:something-wrong:my-package:*:*:*:*:*:*:something:*", "")},
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-2024-0000",
|
||||
Namespace: "alpine:distro:alpine:3.12",
|
||||
},
|
||||
PackageName: "libvncserver",
|
||||
Constraint: version.MustGetConstraint("< 0.9.10", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-azure-autorest-vuln-false-positive",
|
||||
Namespace: "alpine:distro:alpine:3.12",
|
||||
},
|
||||
PackageName: "ko",
|
||||
Constraint: version.MustGetConstraint("< 0", version.ApkFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-npm-false-positive-in-apk-subpackage",
|
||||
Namespace: "alpine:distro:alpine:3.12",
|
||||
},
|
||||
PackageName: "npm-apk-package-with-false-positive",
|
||||
Constraint: version.MustGetConstraint("< 0", version.ApkFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-gentoo-skopeo",
|
||||
Namespace: "gentoo:distro:gentoo:2.8",
|
||||
},
|
||||
PackageName: "app-containers/skopeo",
|
||||
Constraint: version.MustGetConstraint("< 1.6.0", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-coverage-main-module-vuln",
|
||||
Namespace: "github:language:go",
|
||||
},
|
||||
PackageName: "github.com/anchore/coverage",
|
||||
Constraint: version.MustGetConstraint("< 1.4.0", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-uuid-vuln",
|
||||
Namespace: "github:language:go",
|
||||
},
|
||||
PackageName: "github.com/google/uuid",
|
||||
Constraint: version.MustGetConstraint("< 1.4.0", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-azure-autorest-vuln-false-positive",
|
||||
Namespace: "github:language:go",
|
||||
},
|
||||
PackageName: "github.com/azure/go-autorest/autorest",
|
||||
Constraint: version.MustGetConstraint("< 0.11.30", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-bogus-my-package-2-idris",
|
||||
Namespace: "github:language:idris",
|
||||
},
|
||||
PackageName: "my-package",
|
||||
Constraint: version.MustGetConstraint("< 2.0", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-javascript-validator",
|
||||
Namespace: "github:language:javascript",
|
||||
},
|
||||
PackageName: "npm",
|
||||
Constraint: version.MustGetConstraint("> 5, < 7.2.1", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-npm-false-positive-in-apk-subpackage",
|
||||
Namespace: "github:language:javascript",
|
||||
},
|
||||
PackageName: "npm-apk-subpackage-with-false-positive",
|
||||
Constraint: version.MustGetConstraint("< 2.0.0", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-python-pygments",
|
||||
Namespace: "github:language:python",
|
||||
},
|
||||
PackageName: "pygments",
|
||||
Constraint: version.MustGetConstraint("< 2.6.2", version.PythonFormat),
|
||||
},
|
||||
//{
|
||||
// Reference: vulnerability.Reference{
|
||||
// ID: "CVE-my-package-python",
|
||||
// Namespace: "github:language:python",
|
||||
// },
|
||||
// PackageName: "my-package",
|
||||
//},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-ruby-bundler",
|
||||
Namespace: "github:language:ruby", // github:language:gem ??
|
||||
},
|
||||
PackageName: "bundler",
|
||||
Constraint: version.MustGetConstraint("> 2.0.0, <= 2.1.4", version.UnknownFormat), //version.GemFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-java-example-java-app",
|
||||
Namespace: "github:language:java",
|
||||
},
|
||||
PackageName: "org.anchore:example-java-app-maven",
|
||||
Constraint: version.MustGetConstraint(">= 0.0.1, < 1.2.0", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-dotnet-sample",
|
||||
Namespace: "github:language:dotnet",
|
||||
},
|
||||
PackageName: "awssdk.core",
|
||||
Constraint: version.MustGetConstraint(">= 3.7.0.0, < 3.7.12.0", version.UnknownFormat), // was: "dotnet"
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-haskell-sample",
|
||||
Namespace: "github:language:haskell",
|
||||
},
|
||||
PackageName: "shellcheck",
|
||||
Constraint: version.MustGetConstraint("< 0.9.0", version.UnknownFormat), // was: "haskell"
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-hex-plug",
|
||||
Namespace: "github:language:elixir",
|
||||
},
|
||||
PackageName: "plug",
|
||||
Constraint: version.MustGetConstraint("< 1.12.0", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-rust-sample-1",
|
||||
Namespace: "github:language:rust",
|
||||
},
|
||||
PackageName: "hello-auditable",
|
||||
Constraint: version.MustGetConstraint("< 0.2.0", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-rust-sample-2",
|
||||
Namespace: "github:language:rust",
|
||||
},
|
||||
PackageName: "auditable",
|
||||
Constraint: version.MustGetConstraint("< 0.2.0", version.UnknownFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-dpkg-apt",
|
||||
Namespace: "debian:distro:debian:8",
|
||||
},
|
||||
PackageName: "apt-dev",
|
||||
Constraint: version.MustGetConstraint("<= 1.8.2", version.DebFormat), // was: "dpkg"
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-rpmdb-dive",
|
||||
Namespace: "redhat:distro:redhat:8",
|
||||
},
|
||||
PackageName: "dive",
|
||||
Constraint: version.MustGetConstraint("<= 1.0.42", version.RpmFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-2016-3333",
|
||||
Namespace: "msrc:distro:windows:10816",
|
||||
},
|
||||
PackageName: "10816",
|
||||
Constraint: version.MustGetConstraint("3200970 || 878787 || base", version.KBFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-rpmdb-dive",
|
||||
Namespace: "sles:distro:sles:12.5",
|
||||
},
|
||||
PackageName: "dive",
|
||||
Constraint: version.MustGetConstraint("<= 1.0.42", version.RpmFormat),
|
||||
},
|
||||
{
|
||||
Reference: vulnerability.Reference{
|
||||
ID: "CVE-arch-xz-backdoor",
|
||||
Namespace: "arch:distro:arch:rolling",
|
||||
},
|
||||
PackageName: "xz",
|
||||
Constraint: version.MustGetConstraint("< 5.6.1-2", version.PacmanFormat),
|
||||
},
|
||||
}...)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
# the candidate is grype built from this checkout (make quality builds it), the reference is the latest release.
|
||||
# both import the same pinned DB (make update-quality-gate-db moves it), so grype's matching code is the only thing that differs.
|
||||
# the candidate is grype built from this checkout (make integration:quality builds it), the reference is the latest release.
|
||||
# both import the same pinned DB (make integration:update-db moves it), so grype's matching code is the only thing that differs.
|
||||
schema: v1
|
||||
description: grype from this checkout vs the latest grype release, on the pinned DB
|
||||
candidate: {grype: ../bin/grype, db: "https://grype.anchore.io/databases/v6/vulnerability-db_v6.1.9_2026-10-01T00:39:44Z_1790836428.tar.zst@sha256:c0d0263192d91df04b242e9a91e34cb289118fb08f1ed56eb0239eb57d7a517f", config: ../.grype.yaml}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File diff suppressed because it is too large.
Load diff
@@ -1,76 +0,0 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/grype/grype"
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/anchore/grype/grype/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func TestMatchBySBOMDocument(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
expectedIDs []string
|
||||
expectedDetails []match.Detail
|
||||
}{
|
||||
{
|
||||
name: "unknown package type",
|
||||
fixture: "testdata/sbom/syft-sbom-with-unknown-packages.json",
|
||||
expectedIDs: []string{"CVE-bogus-my-package-2-idris"},
|
||||
expectedDetails: []match.Detail{
|
||||
{
|
||||
Type: match.ExactDirectMatch,
|
||||
SearchedBy: match.EcosystemParameters{
|
||||
Language: "idris",
|
||||
Namespace: "github:language:idris",
|
||||
Package: match.PackageParameter{Name: "my-package", Version: "1.0.5"},
|
||||
},
|
||||
Found: match.EcosystemResult{
|
||||
VersionConstraint: "< 2.0 (unknown)",
|
||||
VulnerabilityID: "CVE-bogus-my-package-2-idris",
|
||||
},
|
||||
Matcher: match.StockMatcher,
|
||||
Confidence: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
vp := newMockDbProvider()
|
||||
matches, _, _, err := grype.FindVulnerabilities(vp, fmt.Sprintf("sbom:%s", test.fixture), source.SquashedScope, nil)
|
||||
assert.NoError(t, err)
|
||||
details := make([]match.Detail, 0)
|
||||
ids := strset.New()
|
||||
for _, m := range matches.Sorted() {
|
||||
details = append(details, m.Details...)
|
||||
ids.Add(m.Vulnerability.ID)
|
||||
}
|
||||
|
||||
require.Len(t, details, len(test.expectedDetails))
|
||||
|
||||
cmpOpts := []cmp.Option{
|
||||
cmpopts.IgnoreFields(pkg.Package{}, "Locations"),
|
||||
}
|
||||
|
||||
for i := range test.expectedDetails {
|
||||
if d := cmp.Diff(test.expectedDetails[i], details[i], cmpOpts...); d != "" {
|
||||
t.Errorf("unexpected match details (-want +got):\n%s", d)
|
||||
}
|
||||
}
|
||||
|
||||
assert.ElementsMatch(t, test.expectedIDs, ids.List())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/grype/grype"
|
||||
"github.com/anchore/grype/grype/db/v6/distribution"
|
||||
"github.com/anchore/grype/grype/db/v6/installation"
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/anchore/grype/grype/matcher"
|
||||
"github.com/anchore/grype/grype/pkg"
|
||||
"github.com/anchore/grype/grype/vulnerability"
|
||||
"github.com/anchore/syft/syft"
|
||||
"github.com/anchore/syft/syft/format/spdxjson"
|
||||
"github.com/anchore/syft/syft/format/spdxtagvalue"
|
||||
"github.com/anchore/syft/syft/format/syftjson"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
// pinnedDBRef matches the DB the quality gate pins: the archive URL and its sha256
|
||||
var pinnedDBRef = regexp.MustCompile(`(https://grype\.anchore\.io/databases/v6/[^"@]+)@sha256:([0-9a-f]{64})`)
|
||||
|
||||
// TestSBOMFormats checks that scanning an image matches the same vulnerabilities as scanning an SBOM of that image
|
||||
// in each format. Every format has quirks, so a difference a format is known to cause is listed against it.
|
||||
func TestSBOMFormats(t *testing.T) {
|
||||
store := pinnedDB(t)
|
||||
|
||||
formats := map[string]sbom.FormatEncoder{
|
||||
"syft-json": syftjson.NewFormatEncoder(),
|
||||
"spdx-json": must(spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig())),
|
||||
"spdx-tag-value": must(spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.DefaultEncoderConfig())),
|
||||
}
|
||||
|
||||
// the images are quality gate subjects, so they are pinned by digest and representative of their ecosystem
|
||||
tests := []struct {
|
||||
name string
|
||||
image string
|
||||
// knownFormatLoss lists, by format, the matches (vulnerability-package-version) that differ from the image
|
||||
// scan because the format cannot carry something the image scan used
|
||||
knownFormatLoss map[string][]string
|
||||
}{
|
||||
{name: "alpine", image: "ghcr.io/anchore/test-images/vulnerabilities-alpine-3.12@sha256:55c9ba4e24e15c0467a071d93fead0990b8f04bb60b359b4056a997598aa56a1"},
|
||||
{name: "debian", image: "docker.io/debian:7@sha256:81e88820a7759038ffa61cff59dfcc12d3772c3a2e75b7cfe963c952da2ad264"},
|
||||
{name: "centos", image: "docker.io/anchore/test_images:vulnerabilities-centos@sha256:746d31247006cc06434ce91ccf3523b2c230ff6c378ffed7ca1c60bbb48ea86f"},
|
||||
{name: "arch", image: "ghcr.io/anchore/test-images/archlinux@sha256:a933b27534e5c911e2c660f7090aa497dee763fbbcb214a37207c2320cfedd98"},
|
||||
{name: "gems", image: "ghcr.io/anchore/test-images/gems@sha256:5763c8a225f950961bf01ddec68e36f18e236130e182f2b9290a6e03b9777bfe"},
|
||||
{name: "npm", image: "ghcr.io/anchore/test-images/npm@sha256:ba42ded8613fc643d407a050faf5ab48cfb405ad3ef2015bf6feeb5dff44738d"},
|
||||
{name: "java", image: "ghcr.io/anchore/test-images/java@sha256:10008791acbc5866de04108746a02a0c4029ce3a4400a9b3dad45d7f2245f9da"},
|
||||
{name: "golang", image: "ghcr.io/anchore/test-images/golang@sha256:d1819e59e89e8ea90073460acb4ebb2ee18ccead9fa880dae91e8fc61b19ca1c"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// the image is pulled and cataloged once; each format re-reads the SBOM that catalog produced
|
||||
imagePkgs, _, s, err := pkg.Provide("registry:"+tt.image, providerConfig())
|
||||
require.NoError(t, err)
|
||||
imageMatches := findMatches(store, imagePkgs)
|
||||
require.NotEmpty(t, imageMatches.Sorted(), "the image scan matched nothing, so there is nothing to compare")
|
||||
|
||||
for name, encoder := range formats {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var buf bytes.Buffer
|
||||
require.NoError(t, encoder.Encode(&buf, *s))
|
||||
sbomPkgs, _, _, err := pkg.ProvideFromReader(bytes.NewReader(buf.Bytes()), providerConfig())
|
||||
require.NoError(t, err)
|
||||
sbomMatches := findMatches(store, sbomPkgs)
|
||||
|
||||
fromImage, fromSBOM := matchSet(imageMatches), matchSet(sbomMatches)
|
||||
allowed := strset.New(tt.knownFormatLoss[name]...)
|
||||
onlyImage, onlySBOM := missingFrom(fromImage, fromSBOM, allowed), missingFrom(fromSBOM, fromImage, allowed)
|
||||
|
||||
assert.Empty(t, onlyImage, "matched scanning the image but not the %s SBOM", name)
|
||||
assert.Empty(t, onlySBOM, "matched scanning the %s SBOM but not the image", name)
|
||||
if t.Failed() {
|
||||
logPackageDiffs(t, imagePkgs, sbomPkgs, append(onlyImage, onlySBOM...))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// pinnedDB loads the DB pinned in the quality gate, importing it into a cache dir named by its checksum on first use
|
||||
func pinnedDB(t *testing.T) vulnerability.Provider {
|
||||
gate, err := os.ReadFile(filepath.Join("gates", "pr.yaml"))
|
||||
require.NoError(t, err)
|
||||
ref := pinnedDBRef.FindSubmatch(gate)
|
||||
require.NotNil(t, ref, "no pinned DB in gates/pr.yaml")
|
||||
|
||||
distCfg := distribution.DefaultConfig()
|
||||
installCfg := installation.Config{DBRootDir: filepath.Join(".cache", "grype-db", string(ref[2]))}
|
||||
|
||||
store, _, err := grype.LoadVulnerabilityDB(distCfg, installCfg, false)
|
||||
if err != nil {
|
||||
client, err := distribution.NewClient(distCfg)
|
||||
require.NoError(t, err)
|
||||
curator, err := installation.NewCurator(installCfg, client)
|
||||
require.NoError(t, err)
|
||||
// go-getter checks the archive against the checksum query and does not send it to the server
|
||||
require.NoError(t, curator.Import(fmt.Sprintf("%s?checksum=sha256:%s", ref[1], ref[2])))
|
||||
store, _, err = grype.LoadVulnerabilityDB(distCfg, installCfg, false)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
return store
|
||||
}
|
||||
|
||||
func providerConfig() pkg.ProviderConfig {
|
||||
cfg := pkg.ProviderConfig{
|
||||
SyftProviderConfig: pkg.SyftProviderConfig{
|
||||
SBOMOptions: syft.DefaultCreateSBOMConfig(),
|
||||
Platform: "linux/amd64",
|
||||
},
|
||||
}
|
||||
cfg.SBOMOptions.Search.Scope = source.SquashedScope
|
||||
return cfg
|
||||
}
|
||||
|
||||
func findMatches(store vulnerability.Provider, pkgs []pkg.Package) match.Matches {
|
||||
return grype.FindVulnerabilitiesForPackage(store, matcher.NewDefaultMatchers(matcher.Config{}), pkgs)
|
||||
}
|
||||
|
||||
// matchSet keys each match by vulnerability, package name and version, to the package it matched
|
||||
func matchSet(matches match.Matches) map[string]pkg.Package {
|
||||
out := map[string]pkg.Package{}
|
||||
for _, m := range matches.Sorted() {
|
||||
out[fmt.Sprintf("%s-%s-%s", m.Vulnerability.ID, m.Package.Name, m.Package.Version)] = m.Package
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// missingFrom lists the packages of matches in a that b does not have, other than the allowed ones
|
||||
func missingFrom(a, b map[string]pkg.Package, allowed *strset.Set) []pkg.Package {
|
||||
var out []pkg.Package
|
||||
for k, p := range a {
|
||||
if _, ok := b[k]; !ok && !allowed.Has(k) {
|
||||
out = append(out, p)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// logPackageDiffs shows how the packages behind the differing matches differ between the image and the SBOM, which
|
||||
// is usually the format quirk to name when listing a known loss
|
||||
func logPackageDiffs(t *testing.T, imagePkgs, sbomPkgs []pkg.Package, differing []pkg.Package) {
|
||||
t.Helper()
|
||||
find := func(pkgs []pkg.Package, name, version string) *pkg.Package {
|
||||
for i := range pkgs {
|
||||
if pkgs[i].Name == name && pkgs[i].Version == version {
|
||||
return &pkgs[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
logged := strset.New()
|
||||
for _, p := range differing {
|
||||
key := p.Name + "@" + p.Version
|
||||
if logged.Has(key) {
|
||||
continue
|
||||
}
|
||||
logged.Add(key)
|
||||
diff := cmp.Diff(find(imagePkgs, p.Name, p.Version), find(sbomPkgs, p.Name, p.Version),
|
||||
cmpopts.IgnoreFields(pkg.Package{}, "ID"),
|
||||
// packages hold syft types with unexported fields (location sets, file references)
|
||||
cmp.Exporter(func(reflect.Type) bool { return true }))
|
||||
t.Logf("package %s (-image +sbom):\n%s", key, diff)
|
||||
}
|
||||
}
|
||||
|
||||
func must(e sbom.FormatEncoder, err error) sbom.FormatEncoder {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return e
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
!**/image-*/Dockerfile
|
||||
grype-db
|
||||
grype-db-download*
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
# change these if you want CI to not use previous stored cache
|
||||
INTEGRATION_CACHE_BUSTER := "894d8ca"
|
||||
|
||||
.PHONY: cache.fingerprint
|
||||
cache.fingerprint:
|
||||
find image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | tee /dev/stderr | md5sum | tee cache.fingerprint && echo "$(INTEGRATION_CACHE_BUSTER)" >> cache.fingerprint
|
||||
@@ -1,4 +0,0 @@
|
||||
FROM cgr.dev/chainguard/go AS builder
|
||||
|
||||
FROM scratch
|
||||
COPY . .
|
||||
@@ -1,6 +0,0 @@
|
||||
NAME="Alpine Linux"
|
||||
ID=alpine
|
||||
VERSION_ID=3.12.0
|
||||
PRETTY_NAME="Alpine Linux v3.12"
|
||||
HOME_URL="https://alpinelinux.org/"
|
||||
BUG_REPORT_URL="https://bugs.alpinelinux.org/"
|
||||
@@ -1,58 +0,0 @@
|
||||
C:Q1z0MwWQKfva+S+q7XmOBYFfQgW/k=
|
||||
P:libvncserver
|
||||
V:0.9.9
|
||||
A:x86_64
|
||||
S:166239
|
||||
I:389120
|
||||
T:Library to make writing a vnc server easy
|
||||
U:http://libvncserver.sourceforge.net/
|
||||
L:GPL-2.0-or-later
|
||||
o:libvncserver
|
||||
m:A. Wilcox <awilfox@adelielinux.org>
|
||||
t:1572818861
|
||||
c:bf1ec813f662f128fc6b70f37ef1c0474bb24488
|
||||
D:so:libc.musl-x86_64.so.1 so:libgcrypt.so.20 so:libgnutls.so.30 so:libjpeg.so.8 so:libpng16.so.16 so:libz.so.1
|
||||
p:so:libvncclient.so.1=1.0.0 so:libvncserver.so.1=1.0.0
|
||||
F:usr
|
||||
F:usr/lib
|
||||
R:libvncclient.so.1
|
||||
a:0:0:777
|
||||
Z:Q1quyp/JcSPFQhtQFjMUYdMwRvAWM=
|
||||
R:libvncserver.so.1.0.0
|
||||
a:0:0:755
|
||||
Z:Q16Pd1AqyqQRMwiFfbUt9XkYnkapw=
|
||||
R:libvncserver.so.1
|
||||
a:0:0:777
|
||||
Z:Q184HrHsxEBqnsH4QNxeU5w8alhKI=
|
||||
R:libvncclient.so.1.0.0
|
||||
a:0:0:755
|
||||
Z:Q1IEjCrEwVlQt2GjIsb3o39vcgqMg=
|
||||
|
||||
C:Q1z0MwWQKfva+S+q7XmOBYFfQgW/k=
|
||||
P:ko
|
||||
V:0.15.1
|
||||
A:x86_64
|
||||
S:166239
|
||||
I:389120
|
||||
T:Build and deploy Go applications
|
||||
o:ko
|
||||
t:1572818861
|
||||
R:ko
|
||||
a:0:0:755
|
||||
Z:Q16Pd1AqyqQRMwiFfbUt9XkYnkapw=
|
||||
|
||||
C:Q1z0MwWQKfva+S+q7XmOBYFfQgW/k=
|
||||
P:npm-apk-subpackage-with-false-positive
|
||||
V:7.0.0
|
||||
A:x86_64
|
||||
S:166239
|
||||
I:389120
|
||||
T:NPM package, in an APK subpackage, that has a false positive
|
||||
o:npm-apk-package-with-false-positive
|
||||
t:1572818861
|
||||
F:lib
|
||||
F:lib/node_modules
|
||||
F:lib/node_modules/npm-apk-subpackage-with-false-positive
|
||||
R:package.json
|
||||
a:0:0:755
|
||||
Z:Q16Pd1AqyqQRMwiFfbUt9XkYnkapw=
|
||||
Generated
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "npm-apk-subpackage-with-false-positive",
|
||||
"version": "1.0.0",
|
||||
"description": "NPM package, in an APK subpackage, that has a false positive",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/luhring/grype.git"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
FROM docker.io/archlinux:20191105@sha256:1097437745db73ba839d60b9b9b96e6648e62751519a1319bfccc849f6a3f74c
|
||||
@@ -1,2 +0,0 @@
|
||||
FROM scratch
|
||||
COPY . .
|
||||
@@ -1,11 +0,0 @@
|
||||
NAME="CentOS Linux"
|
||||
VERSION="8 (Core)"
|
||||
ID="centos"
|
||||
ID_LIKE="rhel fedora"
|
||||
VERSION_ID="8"
|
||||
PLATFORM_ID="platform:el8"
|
||||
PRETTY_NAME="CentOS Linux 8 (Core)"
|
||||
ANSI_COLOR="0;31"
|
||||
CPE_NAME="cpe:/o:centos:centos:8"
|
||||
HOME_URL="https://www.centos.org/"
|
||||
BUG_REPORT_URL="https://bugs.centos.org/"
|
||||
Binary file not shown.
-23
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eux
|
||||
|
||||
docker create --name generate-rpmdb-fixture centos:latest sh -c 'tail -f /dev/null'
|
||||
|
||||
function cleanup {
|
||||
docker kill generate-rpmdb-fixture
|
||||
docker rm generate-rpmdb-fixture
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
docker start generate-rpmdb-fixture
|
||||
docker exec -i --tty=false generate-rpmdb-fixture bash <<-EOF
|
||||
mkdir -p /scratch
|
||||
cd /scratch
|
||||
rpm --initdb --dbpath /scratch
|
||||
curl -sSLO https://github.com/wagoodman/dive/releases/download/v0.9.2/dive_0.9.2_linux_amd64.rpm
|
||||
rpm --dbpath /scratch -ivh dive_0.9.2_linux_amd64.rpm
|
||||
rm dive_0.9.2_linux_amd64.rpm
|
||||
rpm --dbpath /scratch -qa
|
||||
EOF
|
||||
|
||||
docker cp generate-rpmdb-fixture:/scratch/Packages .
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM docker.io/golang:1.16@sha256:92ccbb6513249c08e582ca3eafc5c9176dbc5cbfe73af245542c5c78250e9b49
|
||||
WORKDIR /go/src/github.com/anchore/test/
|
||||
COPY golang/ ./
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o go-app .
|
||||
|
||||
FROM scratch
|
||||
COPY --from=0 /go/src/github.com/anchore/test/go-app ./
|
||||
COPY . .
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v6.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v6.0": {
|
||||
"TestLibrary/1.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "6.0.0",
|
||||
"Microsoft.Extensions.Logging": "6.0.0",
|
||||
"Newtonsoft.Json": "13.0.1",
|
||||
"Serilog": "2.10.0",
|
||||
"Serilog.Sinks.Console": "4.0.1",
|
||||
"TestCommon": "1.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"TestLibrary.dll": {}
|
||||
}
|
||||
},
|
||||
"AWSSDK.Core/3.7.10.6": {
|
||||
"runtime": {
|
||||
"lib/netcoreapp3.1/AWSSDK.Core.dll": {
|
||||
"assemblyVersion": "3.3.0.0",
|
||||
"fileVersion": "3.7.10.6"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection/6.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": {
|
||||
"assemblyVersion": "6.0.0.0",
|
||||
"fileVersion": "6.0.21.52210"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions/6.0.0": {
|
||||
"runtime": {
|
||||
"lib/net6.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||
"assemblyVersion": "6.0.0.0",
|
||||
"fileVersion": "6.0.21.52210"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging/6.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "6.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "6.0.0",
|
||||
"Microsoft.Extensions.Options": "6.0.0",
|
||||
"System.Diagnostics.DiagnosticSource": "6.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.1/Microsoft.Extensions.Logging.dll": {
|
||||
"assemblyVersion": "6.0.0.0",
|
||||
"fileVersion": "6.0.21.52210"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions/6.0.0": {
|
||||
"runtime": {
|
||||
"lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll": {
|
||||
"assemblyVersion": "6.0.0.0",
|
||||
"fileVersion": "6.0.21.52210"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options/6.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
|
||||
"Microsoft.Extensions.Primitives": "6.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.1/Microsoft.Extensions.Options.dll": {
|
||||
"assemblyVersion": "6.0.0.0",
|
||||
"fileVersion": "6.0.21.52210"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives/6.0.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net6.0/Microsoft.Extensions.Primitives.dll": {
|
||||
"assemblyVersion": "6.0.0.0",
|
||||
"fileVersion": "6.0.21.52210"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||
"assemblyVersion": "13.0.0.0",
|
||||
"fileVersion": "13.0.1.25517"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Serilog/2.10.0": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.1/Serilog.dll": {
|
||||
"assemblyVersion": "2.0.0.0",
|
||||
"fileVersion": "2.10.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Console/4.0.1": {
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net5.0/Serilog.Sinks.Console.dll": {
|
||||
"assemblyVersion": "4.0.1.0",
|
||||
"fileVersion": "4.0.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.DiagnosticSource/6.0.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe/6.0.0": {},
|
||||
"TestCommon/1.0.0": {
|
||||
"dependencies": {
|
||||
"AWSSDK.Core": "3.7.10.6"
|
||||
},
|
||||
"runtime": {
|
||||
"TestCommon.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"TestLibrary/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"AWSSDK.Core/3.7.10.6": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-kHBB+QmosVaG6DpngXQ8OlLVVNMzltNITfsRr68Z90qO7dSqJ2EHNd8dtBU1u3AQQLqqFHOY0lfmbpexeH6Pew==",
|
||||
"path": "awssdk.core/3.7.10.6",
|
||||
"hashPath": "awssdk.core.3.7.10.6.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
module github.com/anchore/coverage
|
||||
|
||||
go 1.18
|
||||
|
||||
require github.com/google/uuid v1.3.0
|
||||
@@ -1,2 +0,0 @@
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -1,11 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(uuid.New())
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
active-repositories: hackage.haskell.org:merge
|
||||
constraints: any.Cabal ==3.2.1.0,
|
||||
any.Diff ==0.4.1,
|
||||
any.HTTP ==4000.3.16,
|
||||
any.HUnit ==1.6.2.0,
|
||||
any.OneTuple ==0.3.1,
|
||||
tls +compat -hans +network,
|
||||
any.Only ==0.1,
|
||||
any.PyF ==0.10.2.0,
|
||||
any.QuickCheck ==2.14.2,
|
||||
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
|
||||
any.RSA ==2.4.1,
|
||||
any.SHA ==1.6.4.4,
|
||||
void -safe,
|
||||
any.Spock ==0.14.0.0,
|
||||
|
||||
index-state: hackage.haskell.org 2022-07-07T01:01:53Z
|
||||
@@ -1,16 +0,0 @@
|
||||
flags: {}
|
||||
extra-package-dbs: []
|
||||
packages:
|
||||
- .
|
||||
resolver: lts-18.28
|
||||
extra-deps:
|
||||
- ShellCheck-0.8.0@sha256:353c9322847b661e4c6f7c83c2acf8e5c08b682fbe516c7d46c29605937543df,3297
|
||||
- colourista-0.1.0.1@sha256:98353ee0e2f5d97d2148513f084c1cd37dfda03e48aa9dd7a017c9d9c0ba710e,3307
|
||||
- language-docker-11.0.0@sha256:3406ff0c1d592490f53ead8cf2cd22bdf3d79fd125ccaf3add683f6d71c24d55,3883
|
||||
- spdx-1.0.0.2@sha256:7dfac9b454ff2da0abb7560f0ffbe00ae442dd5cb76e8be469f77e6988a70fed,2008
|
||||
- hspec-2.9.4@sha256:658a6a74d5a70c040edd6df2a12228c6d9e63082adaad1ed4d0438ad082a0ef3,1709
|
||||
- hspec-core-2.9.4@sha256:a126e9087409fef8dcafcd2f8656456527ac7bb163ed4d9cb3a57589042a5fe8,6498
|
||||
- hspec-discover-2.9.4@sha256:fbcf49ecfc3d4da53e797fd0275264cba776ffa324ee223e2a3f4ec2d2c9c4a6,2165
|
||||
- stm-2.5.0.2@sha256:e4dc6473faaa75fbd7eccab4e3ee1d651d75bb0e49946ef0b8b751ccde771a55,2314
|
||||
ghc-options:
|
||||
"$everything": -haddock
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
# This file was autogenerated by Stack.
|
||||
# You should not edit this file by hand.
|
||||
# For more information, please see the documentation at:
|
||||
# https://docs.haskellstack.org/en/stable/lock_files
|
||||
|
||||
packages:
|
||||
- completed:
|
||||
hackage: HTTP-4000.3.16@sha256:6042643c15a0b43e522a6693f1e322f05000d519543a84149cb80aeffee34f71,5947
|
||||
pantry-tree:
|
||||
size: 1428
|
||||
sha256: b73a7f6d21cf20bbf819e19039409c9010efb5000d2b72cdd8fd67a9027c14e8
|
||||
original:
|
||||
hackage: HTTP-4000.3.16@sha256:6042643c15a0b43e522a6693f1e322f05000d519543a84149cb80aeffee34f71,5947
|
||||
- completed:
|
||||
hackage: configurator-pg-0.2.6@sha256:cd9b06a458428e493a4d6def725af7ab1ab0fef678fbd871f9586fc7f9aa70be,2849
|
||||
pantry-tree:
|
||||
size: 2463
|
||||
sha256: 97efe7a22afc93033bda5adcffdabc0f1c30dc32b2c3ba02114ce7cd74c942fd
|
||||
original:
|
||||
hackage: configurator-pg-0.2.6@sha256:cd9b06a458428e493a4d6def725af7ab1ab0fef678fbd871f9586fc7f9aa70be,2849
|
||||
- completed:
|
||||
hackage: hasql-dynamic-statements-0.3.1.1@sha256:2cfe6e75990e690f595a87cbe553f2e90fcd738610f6c66749c81cc4396b2cc4,2675
|
||||
pantry-tree:
|
||||
size: 595
|
||||
sha256: b84ae10a5c776f88f546df73bc957a35e61056400b7e805dad0b254612907e97
|
||||
original:
|
||||
hackage: hasql-dynamic-statements-0.3.1.1@sha256:2cfe6e75990e690f595a87cbe553f2e90fcd738610f6c66749c81cc4396b2cc4,2675
|
||||
- completed:
|
||||
hackage: hasql-implicits-0.1.0.4@sha256:0848d3cbc9d94e1e539948fa0be4d0326b26335034161bf8076785293444ca6f,1361
|
||||
pantry-tree:
|
||||
size: 264
|
||||
sha256: d49af8f8749ab7039fa668af4b78f997f7fa2928b4aded6798f573a3d08e76a0
|
||||
original:
|
||||
hackage: hasql-implicits-0.1.0.4@sha256:0848d3cbc9d94e1e539948fa0be4d0326b26335034161bf8076785293444ca6f,1361
|
||||
- completed:
|
||||
hackage: hasql-pool-0.5.2.2@sha256:b56d4dea112d97a2ef4b2749508c0ca646828cb2d77b827e8dc433d249bb2062,2438
|
||||
pantry-tree:
|
||||
size: 412
|
||||
sha256: 2741a33f947d28b4076c798c20c1f646beecd21f5eaf522c8256cbeb34d4d6d0
|
||||
original:
|
||||
hackage: hasql-pool-0.5.2.2@sha256:b56d4dea112d97a2ef4b2749508c0ca646828cb2d77b827e8dc433d249bb2062,2438
|
||||
- completed:
|
||||
hackage: lens-aeson-1.1.3@sha256:52c8eaecd2d1c2a969c0762277c4a8ee72c339a686727d5785932e72ef9c3050,1764
|
||||
pantry-tree:
|
||||
size: 541
|
||||
sha256: b31392b78f2a03111c805f4400007778eb93b49f998ab41dfbebaaf9b5526bad
|
||||
original:
|
||||
hackage: lens-aeson-1.1.3@sha256:52c8eaecd2d1c2a969c0762277c4a8ee72c339a686727d5785932e72ef9c3050,1764
|
||||
- completed:
|
||||
hackage: optparse-applicative-0.16.1.0@sha256:418c22ed6a19124d457d96bc66bd22c93ac22fad0c7100fe4972bbb4ac989731,4982
|
||||
pantry-tree:
|
||||
size: 2979
|
||||
sha256: dd092d843091c08691485d68a1908517079b1bc6f3d73928f37635a19dc27fc1
|
||||
original:
|
||||
hackage: optparse-applicative-0.16.1.0@sha256:418c22ed6a19124d457d96bc66bd22c93ac22fad0c7100fe4972bbb4ac989731,4982
|
||||
- completed:
|
||||
hackage: protolude-0.3.2@sha256:2a38b3dad40d238ab644e234b692c8911423f9d3ed0e36b62287c4a698d92cd1,2240
|
||||
pantry-tree:
|
||||
size: 1594
|
||||
sha256: a36d2912ac552d950ba4476de7d950b56b82dd28e48b9f4d0efee938f10bc525
|
||||
original:
|
||||
hackage: protolude-0.3.2@sha256:2a38b3dad40d238ab644e234b692c8911423f9d3ed0e36b62287c4a698d92cd1,2240
|
||||
- completed:
|
||||
hackage: ptr-0.16.8.2@sha256:708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac,3959
|
||||
pantry-tree:
|
||||
size: 1303
|
||||
sha256: 557c438345de19f82bf01d676100da2a191ef06f624e7a4b90b09ac17cbb52a5
|
||||
original:
|
||||
hackage: ptr-0.16.8.2@sha256:708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac,3959
|
||||
snapshots:
|
||||
- completed:
|
||||
size: 618951
|
||||
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/14.yaml
|
||||
sha256: 4c31d4ef975b0211078862566aedf3b82b6cea569fc2cde4c72a51e5a8d236ce
|
||||
original: lts-19.14
|
||||
@@ -1,3 +0,0 @@
|
||||
%{
|
||||
"plug": {:hex, :plug, "1.11.0", "f17217525597628298998bc3baed9f8ea1fa3f1160aa9871aee6df47a6e4d38e", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2d9c633f0499f9dc5c2fd069161af4e2e7756890b81adcbb2ceaa074e8308876"},
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
-1
@@ -1 +0,0 @@
|
||||
See the syft/cataloger/java/testdata/java-builds dir to generate test fixtures and copy to here manually.
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
{
|
||||
"version": "6.14.6",
|
||||
"name": "npm",
|
||||
"description": "a package manager for JavaScript",
|
||||
"keywords": [
|
||||
"install",
|
||||
"modules",
|
||||
"package manager",
|
||||
"package.json"
|
||||
],
|
||||
"preferGlobal": true,
|
||||
"config": {
|
||||
"publishtest": false
|
||||
},
|
||||
"homepage": "https://docs.npmjs.com/",
|
||||
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/npm/cli"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://npm.community/c/bugs"
|
||||
},
|
||||
"directories": {
|
||||
"bin": "./bin",
|
||||
"doc": "./doc",
|
||||
"lib": "./lib",
|
||||
"man": "./man"
|
||||
},
|
||||
"main": "./lib/npm.js",
|
||||
"bin": {
|
||||
"npm": "./bin/npm-cli.js",
|
||||
"npx": "./bin/npx-cli.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"JSONStream": "^1.3.5",
|
||||
"abbrev": "~1.1.1",
|
||||
"ansicolors": "~0.3.2",
|
||||
"write-file-atomic": "^2.4.3"
|
||||
},
|
||||
"bundleDependencies": [
|
||||
"abbrev",
|
||||
"ansicolors",
|
||||
"ansistyles",
|
||||
"write-file-atomic"
|
||||
],
|
||||
"devDependencies": {
|
||||
"deep-equal": "^1.0.1",
|
||||
"get-stream": "^4.1.0",
|
||||
"licensee": "^7.0.3",
|
||||
"marked": "^0.6.3",
|
||||
"marked-man": "^0.6.0",
|
||||
"npm-registry-couchapp": "^2.7.4",
|
||||
"npm-registry-mock": "^1.3.1",
|
||||
"require-inject": "^1.4.4",
|
||||
"sprintf-js": "^1.1.2",
|
||||
"standard": "^11.0.1",
|
||||
"tacks": "^1.3.0",
|
||||
"tap": "^12.7.0",
|
||||
"tar-stream": "^2.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dumpconf": "env | grep npm | sort | uniq",
|
||||
"prepare": "node bin/npm-cli.js rebuild && node bin/npm-cli.js --no-audit --no-timing prune --prefix=. --no-global && rimraf test/*/*/node_modules && make -j4 mandocs",
|
||||
"preversion": "bash scripts/update-authors.sh && git add AUTHORS && git commit -m \"update AUTHORS\" || true",
|
||||
"licenses": "licensee --production --errors-only",
|
||||
"tap": "tap -J --timeout 300 --no-esm",
|
||||
"tap-cover": "tap -J --nyc-arg=--cache --coverage --timeout 600 --no-esm",
|
||||
"lint": "standard",
|
||||
"pretest": "npm run lint",
|
||||
"test": "npm run test-tap --",
|
||||
"test:nocleanup": "NO_TEST_CLEANUP=1 npm run test --",
|
||||
"sudotest": "sudo npm run tap -- \"test/tap/*.js\"",
|
||||
"sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 npm run tap -- \"test/tap/*.js\"",
|
||||
"posttest": "rimraf test/npm_cache*",
|
||||
"test-coverage": "npm run tap-cover -- \"test/tap/*.js\" \"test/network/*.js\"",
|
||||
"test-tap": "npm run tap -- \"test/tap/*.js\" \"test/network/*.js\"",
|
||||
"test-node": "tap --timeout 240 \"test/tap/*.js\" \"test/network/*.js\""
|
||||
},
|
||||
"license": "Artistic-2.0",
|
||||
"engines": {
|
||||
"node": "6 >=6.2.0 || 8 || >=9.3.0"
|
||||
}
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: Pygments
|
||||
Version: 2.6.1
|
||||
Summary: Pygments is a syntax highlighting package written in Python.
|
||||
Home-page: https://pygments.org/
|
||||
Author: Georg Brandl
|
||||
Author-email: georg@python.org
|
||||
License: BSD License
|
||||
Keywords: syntax highlighting
|
||||
Platform: any
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: End Users/Desktop
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: Development Status :: 6 - Mature
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Topic :: Text Processing :: Filters
|
||||
Classifier: Topic :: Utilities
|
||||
Requires-Python: >=3.5
|
||||
|
||||
|
||||
Pygments
|
||||
~~~~~~~~
|
||||
|
||||
Pygments is a syntax highlighting package written in Python.
|
||||
|
||||
It is a generic syntax highlighter suitable for use in code hosting, forums,
|
||||
wikis or other applications that need to prettify source code. Highlights
|
||||
are:
|
||||
|
||||
* a wide range of over 500 languages and other text formats is supported
|
||||
* special attention is paid to details, increasing quality by a fair amount
|
||||
* support for new languages and formats are added easily
|
||||
* a number of output formats, presently HTML, LaTeX, RTF, SVG, all image formats that PIL supports and ANSI sequences
|
||||
* it is usable as a command-line tool and as a library
|
||||
|
||||
:copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
pygments
|
||||
@@ -1,11 +0,0 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
rails (4.1.1)
|
||||
activerecord (= 4.1.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
rails (= 4.1.1)
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
# -*- encoding: utf-8 -*-
|
||||
# stub: bundler 2.1.4 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "bundler".freeze
|
||||
s.version = "2.1.4"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 2.5.2".freeze) if s.respond_to? :required_rubygems_version=
|
||||
s.metadata = { "bug_tracker_uri" => "https://github.com/bundler/bundler/issues", "changelog_uri" => "https://github.com/bundler/bundler/blob/master/CHANGELOG.md", "homepage_uri" => "https://bundler.io/", "source_code_uri" => "https://github.com/bundler/bundler/" } if s.respond_to? :metadata=
|
||||
s.require_paths = ["lib".freeze]
|
||||
s.authors = ["Andr\u00E9 Arko".freeze, "Samuel Giddins".freeze, "Colby Swandale".freeze, "Hiroshi Shibata".freeze, "David Rodr\u00EDguez".freeze, "Grey Baker".freeze, "Stephanie Morillo".freeze, "Chris Morris".freeze, "James Wen".freeze, "Tim Moore".freeze, "Andr\u00E9 Medeiros".freeze, "Jessica Lynn Suttles".freeze, "Terence Lee".freeze, "Carl Lerche".freeze, "Yehuda Katz".freeze]
|
||||
s.bindir = "exe".freeze
|
||||
s.date = "2020-01-05"
|
||||
s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably".freeze
|
||||
s.email = ["team@bundler.io".freeze]
|
||||
s.executables = ["bundle".freeze, "bundler".freeze]
|
||||
s.files = ["exe/bundle".freeze, "exe/bundler".freeze]
|
||||
s.homepage = "https://bundler.io".freeze
|
||||
s.licenses = ["MIT".freeze]
|
||||
s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze)
|
||||
s.rubygems_version = "3.1.2".freeze
|
||||
s.summary = "The best way to manage your application's dependencies".freeze
|
||||
|
||||
s.installed_by_version = "3.1.2" if s.respond_to? :installed_by_version
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
|
||||
NAME="Debian GNU/Linux"
|
||||
VERSION_ID="8"
|
||||
VERSION="8 (jessie)"
|
||||
ID=debian
|
||||
HOME_URL="http://www.debian.org/"
|
||||
SUPPORT_URL="http://www.debian.org/support"
|
||||
BUG_REPORT_URL="https://bugs.debian.org/"
|
||||
@@ -1,35 +0,0 @@
|
||||
Package: apt
|
||||
Status: install ok installed
|
||||
Priority: required
|
||||
Section: admin
|
||||
Installed-Size: 4064
|
||||
Maintainer: APT Development Team <deity@lists.debian.org>
|
||||
Architecture: amd64
|
||||
Version: 1.8.2
|
||||
Source: apt-dev
|
||||
Replaces: apt-transport-https (<< 1.5~alpha4~), apt-utils (<< 1.3~exp2~)
|
||||
Provides: apt-transport-https (= 1.8.2)
|
||||
Depends: adduser, gpgv | gpgv2 | gpgv1, debian-archive-keyring, libapt-pkg5.0 (>= 1.7.0~alpha3~), libc6 (>= 2.15), libgcc1 (>= 1:3.0), libgnutls30 (>= 3.6.6), libseccomp2 (>= 1.0.1), libstdc++6 (>= 5.2)
|
||||
Recommends: ca-certificates
|
||||
Suggests: apt-doc, aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), gnupg | gnupg2 | gnupg1, powermgmt-base
|
||||
Breaks: apt-transport-https (<< 1.5~alpha4~), apt-utils (<< 1.3~exp2~), aptitude (<< 0.8.10)
|
||||
Conffiles:
|
||||
/etc/apt/apt.conf.d/01autoremove 76120d358bc9037bb6358e737b3050b5
|
||||
/etc/cron.daily/apt-compat 49e9b2cfa17849700d4db735d04244f3
|
||||
/etc/kernel/postinst.d/apt-auto-removal 4ad976a68f045517cf4696cec7b8aa3a
|
||||
/etc/logrotate.d/apt 179f2ed4f85cbaca12fa3d69c2a4a1c3
|
||||
Description: commandline package manager
|
||||
This package provides commandline tools for searching and
|
||||
managing as well as querying information about packages
|
||||
as a low-level access to all features of the libapt-pkg library.
|
||||
.
|
||||
These include:
|
||||
* apt-get for retrieval of packages and information about them
|
||||
from authenticated sources and for installation, upgrade and
|
||||
removal of packages together with their dependencies
|
||||
* apt-cache for querying available information about installed
|
||||
as well as installable packages
|
||||
* apt-cdrom to use removable media as a source for packages
|
||||
* apt-config as an interface to the configuration settings
|
||||
* apt-key as an interface to manage authentication keys
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
FROM scratch
|
||||
COPY . .
|
||||
@@ -1,5 +0,0 @@
|
||||
JAVA_VERSION="1.8.0_400"
|
||||
FULL_VERSION="1.8.0_400-b07"
|
||||
NOPE_SEMANTIC_VERSION="8.0.400+7"
|
||||
IMPLEMENTOR="Oracle"
|
||||
IMAGE_TYPE="JDK"
|
||||
@@ -1,2 +0,0 @@
|
||||
FROM scratch
|
||||
COPY . .
|
||||
@@ -1,8 +0,0 @@
|
||||
NAME=Gentoo
|
||||
ID=gentoo
|
||||
PRETTY_NAME="Gentoo Linux"
|
||||
ANSI_COLOR="1;32"
|
||||
HOME_URL="https://www.gentoo.org/"
|
||||
SUPPORT_URL="https://www.gentoo.org/support/"
|
||||
BUG_REPORT_URL="https://bugs.gentoo.org/"
|
||||
VERSION_ID="2.8"
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
dir /usr
|
||||
dir /usr/bin
|
||||
obj /usr/bin/skopeo 376c02bd3b22804df8fdfdc895e7dbfb 1649284374
|
||||
dir /etc
|
||||
dir /etc/containers
|
||||
obj /etc/containers/policy.json c01eb6950f03419e09d4fc88cb42ff6f 1649284375
|
||||
dir /etc/containers/registries.d
|
||||
obj /etc/containers/registries.d/default.yaml e6e66cd3c24623e0667f26542e0e08f6 1649284375
|
||||
dir /var
|
||||
dir /var/lib
|
||||
dir /var/lib/atomic
|
||||
dir /var/lib/atomic/sigstore
|
||||
obj /var/lib/atomic/sigstore/.keep_app-containers_skopeo-0 d41d8cd98f00b204e9800998ecf8427e 1649284375
|
||||
-1
@@ -1 +0,0 @@
|
||||
Apache-2.0 BSD BSD-2 CC-BY-SA-4.0 ISC MIT
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
27937835
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
# Copyright 1999-2022 Gentoo Authors
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
|
||||
# NOTE: The comments in this file are for instruction and documentation.
|
||||
# They're not meant to appear with your final, production ebuild. Please
|
||||
# remember to remove them before submitting or committing your ebuild. That
|
||||
# doesn't mean you can't add your own comments though.
|
||||
|
||||
# The EAPI variable tells the ebuild format in use.
|
||||
# It is suggested that you use the latest EAPI approved by the Council.
|
||||
# The PMS contains specifications for all EAPIs. Eclasses will test for this
|
||||
# variable if they need to use features that are not universal in all EAPIs.
|
||||
# If an eclass doesn't support latest EAPI, use the previous EAPI instead.
|
||||
EAPI=7
|
||||
|
||||
|
||||
# inherit lists eclasses to inherit functions from. For example, an ebuild
|
||||
# that needs the eautoreconf function from autotools.eclass won't work
|
||||
# without the following line:
|
||||
#inherit autotools
|
||||
#
|
||||
# Eclasses tend to list descriptions of how to use their functions properly.
|
||||
# Take a look at the eclass/ directory for more examples.
|
||||
|
||||
# Short one-line description of this package.
|
||||
DESCRIPTION="This is a sample skeleton ebuild file"
|
||||
@@ -1,2 +0,0 @@
|
||||
# An image containing the example hello-auditable binary from https://github.com/Shnatsel/rust-audit/tree/master/hello-auditable
|
||||
FROM docker.io/tofay/hello-rust-auditable:latest
|
||||
@@ -1,2 +0,0 @@
|
||||
FROM scratch
|
||||
COPY . .
|
||||
@@ -1,9 +0,0 @@
|
||||
NAME="SLES"
|
||||
VERSION="12-SP5"
|
||||
VERSION_ID="12.5"
|
||||
PRETTY_NAME="SUSE Linux Enterprise Server 12 SP5"
|
||||
ID="sles"
|
||||
ID_LIKE="suse"
|
||||
ANSI_COLOR="0;32"
|
||||
CPE_NAME="cpe:/o:suse:sles:12:sp5"
|
||||
DOCUMENTATION_URL="https://documentation.suse.com/"
|
||||
Binary file not shown.
-23
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eux
|
||||
|
||||
docker create --name generate-rpmdb-fixture sles12sp5:latest sh -c 'tail -f /dev/null'
|
||||
|
||||
function cleanup {
|
||||
docker kill generate-rpmdb-fixture
|
||||
docker rm generate-rpmdb-fixture
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
docker start generate-rpmdb-fixture
|
||||
docker exec -i --tty=false generate-rpmdb-fixture bash <<-EOF
|
||||
mkdir -p /scratch
|
||||
cd /scratch
|
||||
rpm --initdb --dbpath /scratch
|
||||
curl -sSLO https://github.com/wagoodman/dive/releases/download/v0.9.2/dive_0.9.2_linux_amd64.rpm
|
||||
rpm --dbpath /scratch -ivh dive_0.9.2_linux_amd64.rpm
|
||||
rm dive_0.9.2_linux_amd64.rpm
|
||||
rpm --dbpath /scratch -qa
|
||||
EOF
|
||||
|
||||
docker cp generate-rpmdb-fixture:/scratch/Packages .
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"artifacts": [
|
||||
{
|
||||
"id": "eeb36c1c-c03a-425b-901f-df918cc3757e",
|
||||
"name": "10816",
|
||||
"version": "3200970",
|
||||
"type": "msrc-kb"
|
||||
}
|
||||
],
|
||||
"artifactRelationships": [],
|
||||
"source": {
|
||||
"type": "image",
|
||||
"target": {
|
||||
"userInput": "my-awesome-image:latest",
|
||||
"scope": "Squashed"
|
||||
}
|
||||
},
|
||||
"distro": {
|
||||
"name": "windows",
|
||||
"version": "10816",
|
||||
"idLike": ""
|
||||
},
|
||||
"descriptor": {
|
||||
"name": "syft",
|
||||
"version": "v0.19.1"
|
||||
},
|
||||
"schema": {
|
||||
"version": "1.1.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-1.1.0.json"
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"artifacts": [
|
||||
{
|
||||
"id": "eeb36c1c-c03a-425b-901f-df918cc3757e",
|
||||
"name": "my-package",
|
||||
"version": "1.0.5",
|
||||
"type": "idris",
|
||||
"language": "idris",
|
||||
"cpes": [
|
||||
"cpe:2.3:a:my-package:my-package:1.0.5:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:bogus:my-package:1.0.5:*:*:*:*:*:*:*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"artifactRelationships": [],
|
||||
"source": {
|
||||
"type": "image",
|
||||
"target": {
|
||||
"userInput": "my-awesome-image:latest",
|
||||
"scope": "Squashed"
|
||||
}
|
||||
},
|
||||
"distro": {
|
||||
"name": "ubuntu",
|
||||
"version": "20.04",
|
||||
"idLike": ""
|
||||
},
|
||||
"descriptor": {
|
||||
"name": "syft",
|
||||
"version": "v0.19.1"
|
||||
},
|
||||
"schema": {
|
||||
"version": "1.1.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-1.1.0.json"
|
||||
}
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"default": [
|
||||
{
|
||||
"type": "insecureAcceptAnything"
|
||||
}
|
||||
],
|
||||
"transports": {
|
||||
"docker-daemon": {
|
||||
"": [
|
||||
{
|
||||
"type": "insecureAcceptAnything"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
-12408
File diff suppressed because it is too large.
Load diff
@@ -1,93 +0,0 @@
|
||||
{
|
||||
"document": {
|
||||
"category": "csaf_vex",
|
||||
"csaf_version": "2.0",
|
||||
"notes": [
|
||||
{
|
||||
"category": "summary",
|
||||
"text": "Example Company VEX document. Unofficial content for demonstration purposes only.",
|
||||
"title": "Author comment"
|
||||
}
|
||||
],
|
||||
"publisher": {
|
||||
"category": "vendor",
|
||||
"name": "Example Company ProductCERT",
|
||||
"namespace": "https://psirt.example.com"
|
||||
},
|
||||
"title": "Example VEX Document",
|
||||
"tracking": {
|
||||
"current_release_date": "2024-04-25T11:00:00.000Z",
|
||||
"generator": {
|
||||
"date": "2024-04-25T11:00:00.000Z",
|
||||
"engine": {
|
||||
"name": "Secvisogram",
|
||||
"version": "1.11.0"
|
||||
}
|
||||
},
|
||||
"id": "2022-EVD-UC-01-A-001",
|
||||
"initial_release_date": "2024-04-25T11:00:00.000Z",
|
||||
"revision_history": [
|
||||
{
|
||||
"date": "2024-04-25T11:00:00.000Z",
|
||||
"number": "1",
|
||||
"summary": "Initial version."
|
||||
}
|
||||
],
|
||||
"status": "final",
|
||||
"version": "1"
|
||||
}
|
||||
},
|
||||
"product_tree": {
|
||||
"branches": [
|
||||
{
|
||||
"branches": [
|
||||
{
|
||||
"branches": [
|
||||
{
|
||||
"category": "product_version",
|
||||
"name": "0.9.9",
|
||||
"product": {
|
||||
"name": "LibVNCServer 0.9.9",
|
||||
"product_id": "CSAFPID-0001",
|
||||
"product_identification_helper": {
|
||||
"purl": "pkg:apk/alpine/libvncserver@0.9.9?arch=x86_64&distro=alpine-3.12.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"category": "product_name",
|
||||
"name": "LibVNCServer"
|
||||
}
|
||||
],
|
||||
"category": "vendor",
|
||||
"name": "Example Company"
|
||||
}
|
||||
]
|
||||
},
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"cve": "CVE-2024-0000",
|
||||
"notes": [
|
||||
{
|
||||
"category": "description",
|
||||
"text": "A CVE affecting libvncserver.",
|
||||
"title": "CVE description"
|
||||
}
|
||||
],
|
||||
"product_status": {
|
||||
"known_affected": [
|
||||
"CSAFPID-0001"
|
||||
]
|
||||
},
|
||||
"remediations": [
|
||||
{
|
||||
"category": "vendor_fix",
|
||||
"details": "Customers should update to version 1.1 of product DEF which fixes the issue.",
|
||||
"product_ids": [
|
||||
"CSAFPID-0001"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
{
|
||||
"document": {
|
||||
"category": "csaf_vex",
|
||||
"csaf_version": "2.0",
|
||||
"notes": [
|
||||
{
|
||||
"category": "summary",
|
||||
"text": "Example Company VEX document. Unofficial content for demonstration purposes only.",
|
||||
"title": "Author comment"
|
||||
}
|
||||
],
|
||||
"publisher": {
|
||||
"category": "vendor",
|
||||
"name": "Example Company ProductCERT",
|
||||
"namespace": "https://psirt.example.com"
|
||||
},
|
||||
"title": "Example VEX Document",
|
||||
"tracking": {
|
||||
"current_release_date": "2024-04-25T11:00:00.000Z",
|
||||
"generator": {
|
||||
"date": "2024-04-25T11:00:00.000Z",
|
||||
"engine": {
|
||||
"name": "Secvisogram",
|
||||
"version": "1.11.0"
|
||||
}
|
||||
},
|
||||
"id": "2022-EVD-UC-01-A-001",
|
||||
"initial_release_date": "2024-04-25T11:00:00.000Z",
|
||||
"revision_history": [
|
||||
{
|
||||
"date": "2024-04-25T11:00:00.000Z",
|
||||
"number": "1",
|
||||
"summary": "Initial version."
|
||||
}
|
||||
],
|
||||
"status": "final",
|
||||
"version": "1"
|
||||
}
|
||||
},
|
||||
"product_tree": {
|
||||
"branches": [
|
||||
{
|
||||
"branches": [
|
||||
{
|
||||
"branches": [
|
||||
{
|
||||
"category": "product_version",
|
||||
"name": "0.9.9",
|
||||
"product": {
|
||||
"name": "LibVNCServer 0.9.9",
|
||||
"product_id": "CSAFPID-0001",
|
||||
"product_identification_helper": {
|
||||
"purl": "pkg:apk/alpine/libvncserver@0.9.9?arch=x86_64&distro=alpine-3.12.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"category": "product_name",
|
||||
"name": "LibVNCServer"
|
||||
}
|
||||
],
|
||||
"category": "vendor",
|
||||
"name": "Example Company"
|
||||
}
|
||||
]
|
||||
},
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"cve": "CVE-2024-0000",
|
||||
"notes": [
|
||||
{
|
||||
"category": "description",
|
||||
"text": "A CVE affecting libvncserver.",
|
||||
"title": "CVE description"
|
||||
}
|
||||
],
|
||||
"product_status": {
|
||||
"under_investigation": [
|
||||
"CSAFPID-0001"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"@context": "https://openvex.dev/ns/v0.2.0",
|
||||
"@id": "https://openvex.dev/docs/public/vex-d4e9020b6d0d26f131d535e055902dd6ccf3e2088bce3079a8cd3588a4b14c78",
|
||||
"author": "The OpenVEX Project <openvex@openssf.org>",
|
||||
"timestamp": "2023-07-17T18:28:47.696004345-06:00",
|
||||
"version": 1,
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": {
|
||||
"name": "CVE-2024-0000"
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:oci/alpine@sha256%3Affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"subcomponents": [
|
||||
{ "@id": "pkg:apk/alpine/libvncserver@0.9.9?arch=x86_64&distro=alpine-3.12.0" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "affected"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"@context": "https://openvex.dev/ns/v0.2.0",
|
||||
"@id": "https://openvex.dev/docs/public/vex-d4e9020b6d0d26f131d535e055902dd6ccf3e2088bce3079a8cd3588a4b14c78",
|
||||
"author": "The OpenVEX Project <openvex@openssf.org>",
|
||||
"timestamp": "2023-07-17T18:28:47.696004345-06:00",
|
||||
"version": 1,
|
||||
"statements": [
|
||||
{
|
||||
"timestamp": "2023-07-16T18:28:47.696004345-06:00",
|
||||
"vulnerability": {
|
||||
"name": "CVE-2024-0000"
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:oci/alpine@sha256%3Affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"subcomponents": [
|
||||
{ "@id": "pkg:apk/alpine/libvncserver@0.9.9?arch=x86_64&distro=alpine-3.12.0" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "under_investigation"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/anchore/syft/syft"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
const cacheDirRelativePath string = "./testdata/cache"
|
||||
|
||||
func PullThroughImageCache(t testing.TB, imageName string) string {
|
||||
cacheDirectory, absErr := filepath.Abs(cacheDirRelativePath)
|
||||
if absErr != nil {
|
||||
t.Fatalf("could not get absolute path of cache directory %s; %v", cacheDirRelativePath, absErr)
|
||||
}
|
||||
|
||||
mkdirError := os.MkdirAll(cacheDirectory, 0755)
|
||||
if mkdirError != nil {
|
||||
t.Fatalf("could not create cache directory %s; %v", cacheDirRelativePath, absErr)
|
||||
}
|
||||
|
||||
re := regexp.MustCompile("[/:]")
|
||||
archiveFileName := fmt.Sprintf("%s.tar", re.ReplaceAllString(imageName, "-"))
|
||||
imageArchivePath := filepath.Join(cacheDirectory, archiveFileName)
|
||||
|
||||
if _, err := os.Stat(imageArchivePath); os.IsNotExist(err) {
|
||||
t.Logf("Cache miss for image %s; copying to archive at %s", imageName, imageArchivePath)
|
||||
saveImage(t, imageName, imageArchivePath)
|
||||
}
|
||||
|
||||
return imageArchivePath
|
||||
}
|
||||
|
||||
func saveImage(t testing.TB, imageName string, destPath string) {
|
||||
sourceImage := fmt.Sprintf("docker://docker.io/%s", imageName)
|
||||
destinationString := fmt.Sprintf("docker-archive:%s", destPath)
|
||||
skopeoPath := filepath.Join(repoRoot(t), ".tool", "skopeo")
|
||||
policyPath := filepath.Join(repoRoot(t), "test", "integration", "testdata", "skopeo-policy.json")
|
||||
|
||||
skopeoCommand := []string{
|
||||
"--policy", policyPath,
|
||||
"copy", "--override-os", "linux", sourceImage, destinationString,
|
||||
}
|
||||
|
||||
cmd := exec.Command(skopeoPath, skopeoCommand...)
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
t.Logf("Stderr: %s", exitError.Stderr)
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Logf("Stdout: %s\n", out)
|
||||
}
|
||||
|
||||
func getSyftSBOM(t testing.TB, image, from string, encoder sbom.FormatEncoder) string {
|
||||
src, err := syft.GetSource(context.Background(), image, syft.DefaultGetSourceConfig().WithSources(from))
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, src.Close())
|
||||
})
|
||||
|
||||
config := syft.DefaultCreateSBOMConfig()
|
||||
|
||||
config.Search.Scope = source.SquashedScope
|
||||
// TODO: relationships are not verified at this time
|
||||
s, err := syft.CreateSBOM(context.Background(), src, config)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, s)
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
err = encoder.Encode(&buf, *s)
|
||||
require.NoError(t, err)
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getMatchSet(matches match.Matches) *strset.Set {
|
||||
s := strset.New()
|
||||
for _, m := range matches.Sorted() {
|
||||
s.Add(fmt.Sprintf("%s-%s-%s", m.Vulnerability.ID, m.Package.Name, m.Package.Version))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func repoRoot(tb testing.TB) string {
|
||||
tb.Helper()
|
||||
root, err := exec.Command("git", "rev-parse", "--show-toplevel").Output()
|
||||
if err != nil {
|
||||
tb.Fatalf("unable to find repo root dir: %+v", err)
|
||||
}
|
||||
absRepoRoot, err := filepath.Abs(strings.TrimSpace(string(root)))
|
||||
if err != nil {
|
||||
tb.Fatal("unable to get abs path to repo root:", err)
|
||||
}
|
||||
return absRepoRoot
|
||||
}
|
||||
Reference in new issue
Block a user