mirror of
https://github.com/anchore/syft.git
synced 2026-10-20 01:57:38 +02:00
Compare commits
@@ -14,23 +14,6 @@ if [ -z "$APPLE_DEVELOPER_ID_CERT_PASS" ]; then
|
||||
exit_with_error "APPLE_DEVELOPER_ID_CERT_PASS not set"
|
||||
fi
|
||||
|
||||
if [ -z "$DOCKER_USERNAME" ]; then
|
||||
exit_with_error "DOCKER_USERNAME not set"
|
||||
fi
|
||||
|
||||
if [ -z "$DOCKER_PASSWORD" ]; then
|
||||
exit_with_error "DOCKER_PASSWORD not set"
|
||||
fi
|
||||
|
||||
if [ -z "$GHCR_USERNAME" ]; then
|
||||
exit_with_error "GHCR_USERNAME not set"
|
||||
fi
|
||||
|
||||
if [ -z "$GHCR_PASSWORD" ]; then
|
||||
exit_with_error "GHCR_PASSWORD not set"
|
||||
fi
|
||||
set -u
|
||||
|
||||
# setup_signing
|
||||
#
|
||||
# preps the MAC_SIGNING_IDENTITY env var for use in the signing process, using production certificate material
|
||||
@@ -46,8 +29,4 @@ setup_signing() {
|
||||
|
||||
# Make this new keychain the user's default keychain, so that codesign will be able to find this certificate when we specify it during signing.
|
||||
security default-keychain -d "user" -s "${KEYCHAIN_PATH}"
|
||||
|
||||
commentary "log into docker -- required for publishing (since the default keychain has now been replaced)"
|
||||
echo "${DOCKER_PASSWORD}" | docker login docker.io -u "${DOCKER_USERNAME}" --password-stdin
|
||||
echo "${GHCR_PASSWORD}" | docker login ghcr.io -u "${GHCR_USERNAME}" --password-stdin
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Uses https://github.com/actions/add-to-project example to add issues to Anchore OSS project
|
||||
name: Add issues to OSS project
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
name: Add issue to project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/anchore/projects/22
|
||||
github-token: ${{ secrets.CI_WRITE_GITHUB_TOKEN }}
|
||||
@@ -97,8 +97,6 @@ jobs:
|
||||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
- uses: docker-practice/actions-setup-docker@v1
|
||||
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
@@ -130,11 +128,6 @@ jobs:
|
||||
- name: Build & publish release artifacts
|
||||
run: make release
|
||||
env:
|
||||
GHCR_USERNAME: ${{ github.actor }}
|
||||
GHCR_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
||||
DOCKER_USERNAME: ${{ secrets.TOOLBOX_DOCKER_USER }}
|
||||
DOCKER_PASSWORD: ${{ secrets.TOOLBOX_DOCKER_PASS }}
|
||||
# we use a different token than GITHUB_SECRETS to additionally allow updating the homebrew repos
|
||||
GITHUB_TOKEN: ${{ secrets.ANCHORE_GIT_READ_TOKEN }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
|
||||
@@ -164,3 +157,44 @@ jobs:
|
||||
with:
|
||||
name: artifacts
|
||||
path: dist/**/*
|
||||
|
||||
release-docker-assets:
|
||||
needs: [release]
|
||||
# code signing requires we run on mac-os runners. docker does not come installed on the mac-os runner
|
||||
# a previous release process installed and configured docker on the mac-os runner which lead to blocked releases
|
||||
# the anchore tools team opted to break this step out to a separate process to remove this work constraint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.TOOLBOX_DOCKER_USER }}
|
||||
password: ${{ secrets.TOOLBOX_DOCKER_PASS }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Restore go cache
|
||||
id: go-cache
|
||||
uses: actions/cache@v2.1.3
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-${{ env.GO_VERSION }}-
|
||||
|
||||
- name: (cache-miss) Bootstrap all project dependencies
|
||||
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
|
||||
run: make bootstrap
|
||||
|
||||
- name: Build & Publish docker images
|
||||
run: make release-docker-assets
|
||||
|
||||
+2
-59
@@ -2,10 +2,6 @@ release:
|
||||
prerelease: auto
|
||||
draft: false
|
||||
|
||||
env:
|
||||
# required to support multi architecture docker builds
|
||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- ./.github/scripts/apple-signing/setup.sh {{ .IsSnapshot }}
|
||||
@@ -19,6 +15,8 @@ builds:
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
- s390x
|
||||
# set the modified timestamp on the output binary to the git timestamp to ensure a reproducible build
|
||||
mod_timestamp: &build-timestamp '{{ .CommitTimestamp }}'
|
||||
env: &build-env
|
||||
@@ -95,58 +93,3 @@ brews:
|
||||
homepage: *website
|
||||
description: *description
|
||||
license: "Apache License 2.0"
|
||||
|
||||
dockers:
|
||||
- image_templates:
|
||||
- "anchore/syft:latest"
|
||||
- "anchore/syft:{{ .Tag }}-amd64"
|
||||
- "anchore/syft:v{{ .Major }}-amd64"
|
||||
- "anchore/syft:v{{ .Major }}.{{ .Minor }}-amd64"
|
||||
- "ghcr.io/anchore/syft:latest"
|
||||
- "ghcr.io/anchore/syft:{{ .Tag }}-amd64"
|
||||
- "ghcr.io/anchore/syft:v{{ .Major }}-amd64"
|
||||
- "ghcr.io/anchore/syft:v{{ .Major }}.{{ .Minor }}-amd64"
|
||||
goarch: amd64
|
||||
dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- "anchore/syft:{{ .Tag }}-arm64v8"
|
||||
- "anchore/syft:v{{ .Major }}-arm64v8"
|
||||
- "anchore/syft:v{{ .Major }}.{{ .Minor }}-arm64v8"
|
||||
- "ghcr.io/anchore/syft:{{ .Tag }}-arm64v8"
|
||||
- "ghcr.io/anchore/syft:v{{ .Major }}-arm64v8"
|
||||
- "ghcr.io/anchore/syft:v{{ .Major }}.{{ .Minor }}-arm64v8"
|
||||
goarch: arm64
|
||||
dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64/v8"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
docker_manifests:
|
||||
- name_template: anchore/syft:{{ .Tag }}
|
||||
image_templates:
|
||||
- anchore/syft:v{{ .Major }}.{{ .Minor }}-amd64
|
||||
- anchore/syft:v{{ .Major }}.{{ .Minor }}-arm64v8
|
||||
- name_template: anchore/syft:latest
|
||||
image_templates:
|
||||
- anchore/syft:v{{ .Major }}.{{ .Minor }}-amd64
|
||||
- anchore/syft:v{{ .Major }}.{{ .Minor }}-arm64v8
|
||||
- name_template: ghcr.io/anchore/syft:{{ .Tag }}
|
||||
image_templates:
|
||||
- ghcr.io/anchore/syft:v{{ .Major }}.{{ .Minor }}-amd64
|
||||
- ghcr.io/anchore/syft:v{{ .Major }}.{{ .Minor }}-arm64v8
|
||||
- name_template: ghcr.io/anchore/syft:latest
|
||||
image_templates:
|
||||
- ghcr.io/anchore/syft:v{{ .Major }}.{{ .Minor }}-amd64
|
||||
- ghcr.io/anchore/syft:v{{ .Major }}.{{ .Minor }}-arm64v8
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
# Separate docker configuration to isolate docker dependency away from
|
||||
# mac-os runner on github actions.
|
||||
# See:
|
||||
# https://github.com/anchore/syft/issues/577
|
||||
# https://github.com/anchore/syft/issues/519
|
||||
# https://github.com/anchore/syft/issues/576
|
||||
release:
|
||||
disable: true
|
||||
|
||||
env:
|
||||
# required to support multi architecture docker builds
|
||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
|
||||
builds:
|
||||
- id: linux-build
|
||||
dir: ./cmd/syft
|
||||
binary: syft
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
- s390x
|
||||
# set the modified timestamp on the output binary to the git timestamp to ensure a reproducible build
|
||||
mod_timestamp: &build-timestamp '{{ .CommitTimestamp }}'
|
||||
env: &build-env
|
||||
- CGO_ENABLED=0
|
||||
ldflags: &build-ldflags |
|
||||
-w
|
||||
-s
|
||||
-extldflags '-static'
|
||||
-X github.com/anchore/syft/internal/version.version={{.Version}}
|
||||
-X github.com/anchore/syft/internal/version.gitCommit={{.Commit}}
|
||||
-X github.com/anchore/syft/internal/version.buildDate={{.Date}}
|
||||
-X github.com/anchore/syft/internal/version.gitDescription={{.Summary}}
|
||||
|
||||
dockers:
|
||||
- image_templates:
|
||||
- anchore/syft:debug
|
||||
- anchore/syft:{{.Tag}}-debug
|
||||
- ghcr.io/anchore/syft:debug
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug
|
||||
goarch: amd64
|
||||
dockerfile: Dockerfile.debug
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:debug-arm64v8
|
||||
- anchore/syft:{{.Tag}}-debug-arm64v8
|
||||
- ghcr.io/anchore/syft:debug-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
|
||||
goarch: arm64
|
||||
dockerfile: Dockerfile.debug
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64/v8"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:debug-ppc64le
|
||||
- anchore/syft:{{.Tag}}-debug-ppc64le
|
||||
- ghcr.io/anchore/syft:debug-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
|
||||
goarch: ppc64le
|
||||
dockerfile: Dockerfile.debug
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/ppc64le"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:debug-s390x
|
||||
- anchore/syft:{{.Tag}}-debug-s390x
|
||||
- ghcr.io/anchore/syft:debug-s390x
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
|
||||
goarch: s390x
|
||||
dockerfile: Dockerfile.debug
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/s390x"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:latest
|
||||
- anchore/syft:{{.Tag}}
|
||||
- ghcr.io/anchore/syft:latest
|
||||
- ghcr.io/anchore/syft:{{.Tag}}
|
||||
goarch: amd64
|
||||
dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:{{.Tag}}-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
|
||||
goarch: arm64
|
||||
dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64/v8"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:{{.Tag}}-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
|
||||
goarch: ppc64le
|
||||
dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/ppc64le"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:{{.Tag}}-s390x
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-s390x
|
||||
goarch: s390x
|
||||
dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/s390x"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
docker_manifests:
|
||||
- name_template: anchore/syft:latest
|
||||
image_templates:
|
||||
- anchore/syft:{{.Tag}}
|
||||
- anchore/syft:{{.Tag}}-arm64v8
|
||||
- anchore/syft:{{.Tag}}-ppc64le
|
||||
- anchore/syft:{{.Tag}}-s390x
|
||||
|
||||
- name_template: anchore/syft:debug
|
||||
- anchore/syft:{{.Tag}}-debug
|
||||
- anchore/syft:{{.Tag}}-debug-arm64v8
|
||||
- anchore/syft:{{.Tag}}-debug-ppc64le
|
||||
- anchore/syft:{{.Tag}}-debug-s390x
|
||||
|
||||
- name_template: anchore/syft:{{.Tag}}
|
||||
image_templates:
|
||||
- anchore/syft:{{.Tag}}
|
||||
- anchore/syft:{{.Tag}}-arm64v8
|
||||
- anchore/syft:{{.Tag}}-ppc64le
|
||||
- anchore/syft:{{.Tag}}-s390x
|
||||
|
||||
- name_template: ghcr.io/anchore/syft:latest
|
||||
image_templates:
|
||||
- ghcr.io/anchore/syft:{{.Tag}}
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-s390x
|
||||
|
||||
- name_template: ghcr.io/anchore/syft:debug
|
||||
image_templates:
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
|
||||
|
||||
- name_template: ghcr.io/anchore/syft:{{.Tag}}
|
||||
image_templates:
|
||||
- ghcr.io/anchore/syft:{{.Tag}}
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-s390x
|
||||
+1
-4
@@ -1,6 +1,4 @@
|
||||
FROM alpine:latest AS build
|
||||
|
||||
RUN apk --no-cache add ca-certificates
|
||||
FROM gcr.io/distroless/static-debian11:debug AS build
|
||||
|
||||
FROM scratch
|
||||
# needed for version check HTTPS request
|
||||
@@ -27,6 +25,5 @@ LABEL org.opencontainers.image.licenses="Apache-2.0"
|
||||
LABEL io.artifacthub.package.readme-url="https://raw.githubusercontent.com/anchore/syft/main/README.md"
|
||||
LABEL io.artifacthub.package.logo-url="https://user-images.githubusercontent.com/5199289/136844524-1527b09f-c5cb-4aa9-be54-5aa92a6086c1.png"
|
||||
LABEL io.artifacthub.package.license="Apache-2.0"
|
||||
|
||||
|
||||
ENTRYPOINT ["/syft"]
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
FROM gcr.io/distroless/static-debian11:debug
|
||||
|
||||
# create the /tmp dir, which is needed for image content cache
|
||||
WORKDIR /tmp
|
||||
|
||||
COPY syft /
|
||||
|
||||
ARG BUILD_DATE
|
||||
ARG BUILD_VERSION
|
||||
ARG VCS_REF
|
||||
ARG VCS_URL
|
||||
|
||||
LABEL org.opencontainers.image.created=$BUILD_DATE
|
||||
LABEL org.opencontainers.image.title="syft"
|
||||
LABEL org.opencontainers.image.description="CLI tool and library for generating a Software Bill of Materials from container images and filesystems"
|
||||
LABEL org.opencontainers.image.source=$VCS_URL
|
||||
LABEL org.opencontainers.image.revision=$VCS_REF
|
||||
LABEL org.opencontainers.image.vendor="Anchore, Inc."
|
||||
LABEL org.opencontainers.image.version=$BUILD_VERSION
|
||||
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
||||
LABEL io.artifacthub.package.readme-url="https://raw.githubusercontent.com/anchore/syft/main/README.md"
|
||||
LABEL io.artifacthub.package.logo-url="https://user-images.githubusercontent.com/5199289/136844524-1527b09f-c5cb-4aa9-be54-5aa92a6086c1.png"
|
||||
LABEL io.artifacthub.package.license="Apache-2.0"
|
||||
|
||||
ENTRYPOINT ["/syft"]
|
||||
@@ -32,7 +32,7 @@ BOOTSTRAP_CACHE="c7afb99ad"
|
||||
DISTDIR=./dist
|
||||
SNAPSHOTDIR=./snapshot
|
||||
OS=$(shell uname | tr '[:upper:]' '[:lower:]')
|
||||
SNAPSHOT_BIN=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(OS)-build_$(OS)_amd64/$(BIN))
|
||||
SNAPSHOT_BIN=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(OS)-build_$(OS)_amd64_v1/$(BIN))
|
||||
|
||||
## Variable assertions
|
||||
|
||||
@@ -106,12 +106,12 @@ $(TEMPDIR):
|
||||
.PHONY: bootstrap-tools
|
||||
bootstrap-tools: $(TEMPDIR)
|
||||
GO111MODULE=off GOBIN=$(shell realpath $(TEMPDIR)) go get -u golang.org/x/perf/cmd/benchstat
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.45.0
|
||||
curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.3.0
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.47.2
|
||||
curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.4.0
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/chronicle/main/install.sh | sh -s -- -b $(TEMPDIR)/ v0.3.0
|
||||
.github/scripts/goreleaser-install.sh -d -b $(TEMPDIR)/ v1.4.1
|
||||
.github/scripts/goreleaser-install.sh -d -b $(TEMPDIR)/ v1.10.3
|
||||
GOBIN="$(shell realpath $(TEMPDIR))" go install github.com/neilpa/yajsv@v1.4.0
|
||||
GOBIN="$(shell realpath $(TEMPDIR))" go install github.com/sigstore/cosign/cmd/cosign@v1.5.1
|
||||
GOBIN="$(shell realpath $(TEMPDIR))" go install github.com/sigstore/cosign/cmd/cosign@v1.10.0
|
||||
|
||||
.PHONY: bootstrap-go
|
||||
bootstrap-go:
|
||||
@@ -263,6 +263,18 @@ snapshot-with-signing: ## Build snapshot release binaries and packages (with dum
|
||||
# remove the keychain with the trusted self-signed cert automatically
|
||||
.github/scripts/apple-signing/cleanup.sh
|
||||
|
||||
snapshot-docker-assets: # Build snapshot images of docker images that will be published on release
|
||||
$(call title,Building snapshot docker release assets)
|
||||
|
||||
# create a config with the dist dir overridden
|
||||
echo "dist: $(DISTDIR)" > $(TEMPDIR)/goreleaser.yaml
|
||||
cat .goreleaser_docker.yaml >> $(TEMPDIR)/goreleaser.yaml
|
||||
|
||||
bash -c "\
|
||||
$(SNAPSHOT_CMD) \
|
||||
--config $(TEMPDIR)/goreleaser.yaml \
|
||||
--parallelism 1"
|
||||
|
||||
# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately
|
||||
.PHONY: compare-mac
|
||||
compare-mac: $(RESULTSDIR) $(SNAPSHOTDIR) ## Run compare tests on build snapshot binaries and packages (Mac)
|
||||
@@ -342,6 +354,18 @@ release: clean-dist CHANGELOG.md ## Build and publish final binaries and packag
|
||||
# upload the version file that supports the application version update check (excluding pre-releases)
|
||||
.github/scripts/update-version-file.sh "$(DISTDIR)" "$(VERSION)"
|
||||
|
||||
.PHONY: release-docker-assets
|
||||
release-docker-assets:
|
||||
$(call title,Publishing docker release assets)
|
||||
|
||||
# create a config with the dist dir overridden
|
||||
echo "dist: $(DISTDIR)" > $(TEMPDIR)/goreleaser.yaml
|
||||
cat .goreleaser_docker.yaml >> $(TEMPDIR)/goreleaser.yaml
|
||||
|
||||
bash -c "\
|
||||
$(RELEASE_CMD) \
|
||||
--config $(TEMPDIR)/goreleaser.yaml \
|
||||
--parallelism 1"
|
||||
|
||||
.PHONY: clean
|
||||
clean: clean-dist clean-snapshot clean-test-image-cache ## Remove previous builds, result reports, and test cache
|
||||
@@ -369,7 +393,7 @@ clean-test-image-tar-cache: ## Delete all test cache (built docker image tars)
|
||||
|
||||
.PHONY: clear-test-image-docker-cache
|
||||
clean-test-image-docker-cache: ## Purge all test docker images
|
||||
docker images --format '{{.ID}} {{.Repository}}' | grep stereoscope-fixture- | awk '{print $$1}' | uniq | xargs docker rmi --force
|
||||
docker images --format '{{.ID}} {{.Repository}}' | grep stereoscope-fixture- | awk '{print $$1}' | uniq | xargs -r docker rmi --force
|
||||
|
||||
.PHONY: show-test-image-cache
|
||||
show-test-image-cache: ## Show all docker and image tar cache
|
||||
|
||||
@@ -35,7 +35,9 @@ A CLI tool and Go library for generating a Software Bill of Materials (SBOM) fro
|
||||
- Dart (pubs)
|
||||
- Debian (dpkg)
|
||||
- Dotnet (deps.json)
|
||||
- Objective-C (cocoapods)
|
||||
- Go (go.mod, Go binaries)
|
||||
- Haskell (cabal, stack)
|
||||
- Java (jar, ear, war, par, sar)
|
||||
- JavaScript (npm, yarn)
|
||||
- Jenkins Plugins (jpi, hpi)
|
||||
@@ -44,6 +46,7 @@ A CLI tool and Go library for generating a Software Bill of Materials (SBOM) fro
|
||||
- Red Hat (rpm)
|
||||
- Ruby (gem)
|
||||
- Rust (cargo.lock)
|
||||
- Swift (cocoapods)
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -179,14 +182,15 @@ syft path/to/dir
|
||||
Sources can be explicitly provided with a scheme:
|
||||
|
||||
```
|
||||
docker:yourrepo/yourimage:tag use images from the Docker daemon
|
||||
podman:yourrepo/yourimage:tag use images from the Podman daemon
|
||||
docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
|
||||
oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
|
||||
oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
|
||||
dir:path/to/yourproject read directly from a path on disk (any directory)
|
||||
file:path/to/yourproject/file read directly from a path on disk (any single file)
|
||||
registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
|
||||
docker:yourrepo/yourimage:tag use images from the Docker daemon
|
||||
podman:yourrepo/yourimage:tag use images from the Podman daemon
|
||||
docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
|
||||
oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
|
||||
oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
|
||||
singularity:path/to/yourimage.sif read directly from a Singularity Image Format (SIF) container on disk
|
||||
dir:path/to/yourproject read directly from a path on disk (any directory)
|
||||
file:path/to/yourproject/file read directly from a path on disk (any single file)
|
||||
registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
|
||||
```
|
||||
|
||||
### Excluding file paths
|
||||
@@ -409,6 +413,8 @@ platform: ""
|
||||
# - dartlang-lock
|
||||
# - rust
|
||||
# - dotnet-deps
|
||||
# rust-audit-binary scans Rust binaries built with https://github.com/Shnatsel/rust-audit
|
||||
# - rust-audit-binary
|
||||
catalogers:
|
||||
|
||||
# cataloging packages is exposed through the packages and power-user subcommands
|
||||
|
||||
@@ -102,7 +102,7 @@ func Run(ctx context.Context, app *config.Application, ko sigopts.KeyOpts, args
|
||||
subscription := eventBus.Subscribe()
|
||||
|
||||
return eventloop.EventLoop(
|
||||
execWorker(app, *si, format, predicateType, sv),
|
||||
execWorker(app, *si, format, predicateType, sv, app.File),
|
||||
eventloop.SetupSignals(),
|
||||
subscription,
|
||||
stereoscope.Cleanup,
|
||||
@@ -137,7 +137,7 @@ func parseImageSource(userInput string, app *config.Application) (s *source.Inpu
|
||||
return si, nil
|
||||
}
|
||||
|
||||
func execWorker(app *config.Application, sourceInput source.Input, format sbom.Format, predicateType string, sv *sign.SignerVerifier) <-chan error {
|
||||
func execWorker(app *config.Application, sourceInput source.Input, format sbom.Format, predicateType string, sv *sign.SignerVerifier, file string) <-chan error {
|
||||
errs := make(chan error)
|
||||
go func() {
|
||||
defer close(errs)
|
||||
@@ -163,7 +163,7 @@ func execWorker(app *config.Application, sourceInput source.Input, format sbom.F
|
||||
return
|
||||
}
|
||||
|
||||
err = generateAttestation(app, sbomBytes, src, sv, predicateType)
|
||||
err = generateAttestation(app, sbomBytes, src, sv, predicateType, file)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
@@ -172,7 +172,7 @@ func execWorker(app *config.Application, sourceInput source.Input, format sbom.F
|
||||
return errs
|
||||
}
|
||||
|
||||
func generateAttestation(app *config.Application, predicate []byte, src *source.Source, sv *sign.SignerVerifier, predicateType string) error {
|
||||
func generateAttestation(app *config.Application, predicate []byte, src *source.Source, sv *sign.SignerVerifier, predicateType string, file string) error {
|
||||
switch len(src.Image.Metadata.RepoDigests) {
|
||||
case 0:
|
||||
return fmt.Errorf("cannot generate attestation since no repo digests were found; make sure you're passing an OCI registry source for the attest command")
|
||||
@@ -219,7 +219,12 @@ func generateAttestation(app *config.Application, predicate []byte, src *source.
|
||||
bus.Publish(partybus.Event{
|
||||
Type: event.Exit,
|
||||
Value: func() error {
|
||||
_, err := os.Stdout.Write(signedPayload)
|
||||
var err error
|
||||
if file != "" {
|
||||
err = os.WriteFile(file, signedPayload, 0600)
|
||||
} else {
|
||||
_, err = os.Stdout.Write(signedPayload)
|
||||
}
|
||||
return err
|
||||
},
|
||||
})
|
||||
|
||||
@@ -53,7 +53,7 @@ func parseOutputs(outputs []string, defaultFile, templateFilePath string) (out [
|
||||
|
||||
format := syft.FormatByName(name)
|
||||
if format == nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("bad output format: '%s'", name))
|
||||
errs = multierror.Append(errs, fmt.Errorf(`unsupported output format "%s", supported formats are: %+v`, name, FormatAliases(syft.FormatIDs()...)))
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ func TestIsSupportedFormat(t *testing.T) {
|
||||
{
|
||||
outputs: []string{"unknown"},
|
||||
wantErr: func(t assert.TestingT, err error, bla ...interface{}) bool {
|
||||
return assert.ErrorContains(t, err, "bad output format: 'unknown'")
|
||||
return assert.ErrorContains(t, err, `unsupported output format "unknown", supported formats are: [`)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
packagesExample = ` {{.appName}} {{.command}} alpine:latest a summary of discovered packages
|
||||
packagesExample = ` {{.appName}} {{.command}} alpine:latest a summary of discovered packages
|
||||
{{.appName}} {{.command}} alpine:latest -o json show all possible cataloging details
|
||||
{{.appName}} {{.command}} alpine:latest -o cyclonedx show a CycloneDX formatted SBOM
|
||||
{{.appName}} {{.command}} alpine:latest -o cyclonedx-json show a CycloneDX JSON formatted SBOM
|
||||
@@ -28,15 +28,16 @@ const (
|
||||
`
|
||||
|
||||
schemeHelpHeader = "You can also explicitly specify the scheme to use:"
|
||||
imageSchemeHelp = ` {{.appName}} {{.command}} docker:yourrepo/yourimage:tag explicitly use the Docker daemon
|
||||
{{.appName}} {{.command}} podman:yourrepo/yourimage:tag explicitly use the Podman daemon
|
||||
{{.appName}} {{.command}} registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
|
||||
{{.appName}} {{.command}} docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
|
||||
{{.appName}} {{.command}} oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
|
||||
{{.appName}} {{.command}} oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
|
||||
imageSchemeHelp = ` {{.appName}} {{.command}} docker:yourrepo/yourimage:tag explicitly use the Docker daemon
|
||||
{{.appName}} {{.command}} podman:yourrepo/yourimage:tag explicitly use the Podman daemon
|
||||
{{.appName}} {{.command}} registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
|
||||
{{.appName}} {{.command}} docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
|
||||
{{.appName}} {{.command}} oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
|
||||
{{.appName}} {{.command}} oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
|
||||
{{.appName}} {{.command}} singularity:path/to/yourimage.sif read directly from a Singularity Image Format (SIF) container on disk
|
||||
`
|
||||
nonImageSchemeHelp = ` {{.appName}} {{.command}} dir:path/to/yourproject read directly from a path on disk (any directory)
|
||||
{{.appName}} {{.command}} file:path/to/yourproject/file read directly from a path on disk (any single file)
|
||||
nonImageSchemeHelp = ` {{.appName}} {{.command}} dir:path/to/yourproject read directly from a path on disk (any directory)
|
||||
{{.appName}} {{.command}} file:path/to/yourproject/file read directly from a path on disk (any single file)
|
||||
`
|
||||
packagesSchemeHelp = "\n" + indent + schemeHelpHeader + "\n" + imageSchemeHelp + nonImageSchemeHelp
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@ require (
|
||||
github.com/CycloneDX/cyclonedx-go v0.5.2
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
|
||||
github.com/acobaugh/osrelease v0.1.0
|
||||
github.com/adrg/xdg v0.2.1
|
||||
github.com/adrg/xdg v0.3.3
|
||||
github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074
|
||||
github.com/anchore/client-go v0.0.0-20210222170800-9c70f9b80bcf
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7
|
||||
github.com/anchore/stereoscope v0.0.0-20220628191509-5bd627c0f9ce
|
||||
github.com/anchore/stereoscope v0.0.0-20220802140318-49d33a1fb915
|
||||
github.com/antihax/optional v1.0.0
|
||||
github.com/bmatcuk/doublestar/v4 v4.0.2
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
@@ -26,6 +26,7 @@ require (
|
||||
github.com/jinzhu/copier v0.3.2
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
@@ -37,10 +38,10 @@ require (
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spdx/tools-golang v0.2.0
|
||||
github.com/spf13/afero v1.8.2
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.12.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/vifraa/gopom v0.1.0
|
||||
github.com/wagoodman/go-partybus v0.0.0-20210627031916-db1f5573bbc5
|
||||
github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240
|
||||
@@ -48,30 +49,28 @@ require (
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
|
||||
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Masterminds/sprig/v3 v3.2.2
|
||||
github.com/docker/docker v20.10.12+incompatible
|
||||
github.com/google/go-containerregistry v0.8.1-0.20220209165246-a44adc326839
|
||||
github.com/in-toto/in-toto-golang v0.3.4-0.20211211042327-af1f9fb822bf
|
||||
github.com/knqyf263/go-rpmdb v0.0.0-20220530130908-5101b033fa0d
|
||||
github.com/sigstore/cosign v1.9.0
|
||||
github.com/sigstore/rekor v0.4.1-0.20220114213500-23f583409af3
|
||||
github.com/sigstore/sigstore v1.2.1-0.20220424143412-3d41663116d5
|
||||
github.com/docker/docker v20.10.17+incompatible
|
||||
github.com/google/go-containerregistry v0.10.0
|
||||
github.com/in-toto/in-toto-golang v0.3.4-0.20220709202702-fa494aaa0add
|
||||
github.com/knqyf263/go-rpmdb v0.0.0-20220629110411-9a3bd2ebb923
|
||||
github.com/sigstore/cosign v1.10.0
|
||||
github.com/sigstore/rekor v0.9.1
|
||||
github.com/sigstore/sigstore v1.2.1-0.20220614141825-9c0e2e247545
|
||||
github.com/vbatts/go-mtree v0.5.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
bitbucket.org/creachadair/shell v0.0.6 // indirect
|
||||
cloud.google.com/go v0.100.2 // indirect
|
||||
cloud.google.com/go/compute v1.6.1 // indirect
|
||||
cloud.google.com/go/iam v0.3.0 // indirect
|
||||
cloud.google.com/go/storage v1.22.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v63.3.0+incompatible // indirect
|
||||
bitbucket.org/creachadair/shell v0.0.7 // indirect
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.27 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||
@@ -80,33 +79,33 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/CalebQ42/squashfs v0.5.4 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/PaesslerAG/gval v1.0.0 // indirect
|
||||
github.com/PaesslerAG/jsonpath v0.1.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.14.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.9.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.11.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.3.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.15.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.12.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.10.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.15.0 // indirect
|
||||
github.com/aws/smithy-go v1.11.2 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.7 // indirect
|
||||
github.com/aws/smithy-go v1.11.3 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220517224237-e6f29200ae04 // indirect
|
||||
github.com/benbjohnson/clock v1.1.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chrismellard/docker-credential-acr-env v0.0.0-20220119192733-fe33c00cee21 // indirect
|
||||
@@ -114,46 +113,46 @@ require (
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
|
||||
github.com/containerd/containerd v1.5.13 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.10.1 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.1.0 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.11.4 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.2.0 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20210823021906-dc406ceaf94b // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/docker/cli v20.10.12+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/cli v20.10.17+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fullstorydev/grpcurl v1.8.2 // indirect
|
||||
github.com/fullstorydev/grpcurl v1.8.6 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-chi/chi v4.1.2+incompatible // indirect
|
||||
github.com/go-logr/logr v1.2.2 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.21.2 // indirect
|
||||
github.com/go-openapi/errors v0.20.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/loads v0.21.1 // indirect
|
||||
github.com/go-openapi/runtime v0.24.1 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.2 // indirect
|
||||
github.com/go-openapi/spec v0.20.6 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.3 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/go-openapi/validate v0.21.0 // indirect
|
||||
github.com/go-openapi/validate v0.22.0 // indirect
|
||||
github.com/go-piv/piv-go v1.9.0 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.10.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.11.0 // indirect
|
||||
github.com/go-restruct/restruct v1.2.0-alpha // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
@@ -161,18 +160,18 @@ require (
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.2 // indirect
|
||||
github.com/google/go-github/v42 v42.0.0 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.3 // indirect
|
||||
github.com/google/go-github/v45 v45.2.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/trillian v1.4.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||
github.com/google/trillian v1.4.1 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
github.com/googleapis/go-type-adapters v1.0.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
||||
@@ -182,14 +181,14 @@ require (
|
||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jedisct1/go-minisign v0.0.0-20210703085342-c1f07ee84431 // indirect
|
||||
github.com/jhump/protoreflect v1.9.0 // indirect
|
||||
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b // indirect
|
||||
github.com/jhump/protoreflect v1.10.3 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/jonboulle/clockwork v0.3.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/klauspost/compress v1.14.2 // indirect
|
||||
github.com/klauspost/compress v1.15.4 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20220331220046-b23ab962616e // indirect
|
||||
@@ -211,12 +210,13 @@ require (
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.2 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.6 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.12.1 // indirect
|
||||
github.com/prometheus/client_golang v1.12.2 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/common v0.34.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
@@ -230,20 +230,22 @@ require (
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.1.0 // indirect
|
||||
github.com/stretchr/objx v0.3.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.1.1 // indirect
|
||||
github.com/stretchr/objx v0.4.0 // indirect
|
||||
github.com/subosito/gotenv v1.3.0 // indirect
|
||||
github.com/sylabs/sif/v2 v2.7.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 // indirect
|
||||
github.com/thales-e-security/pool v0.0.2 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.3.0 // indirect
|
||||
github.com/therootcompany/xz v1.0.1 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.3.1 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||
github.com/transparency-dev/merkle v0.0.1 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/urfave/cli v1.22.5 // indirect
|
||||
github.com/urfave/cli v1.22.7 // indirect
|
||||
github.com/vbatts/tar-split v0.11.2 // indirect
|
||||
github.com/xanzy/go-gitlab v0.68.0 // indirect
|
||||
github.com/xanzy/go-gitlab v0.69.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
@@ -251,50 +253,47 @@ require (
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
github.com/zeebo/errs v1.2.2 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.305.4 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/etcdctl/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/etcdutl/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/server/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/tests/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/v3 v3.5.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.8.3 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.306.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/etcdctl/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/etcdutl/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/server/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/tests/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/v3 v3.6.0-alpha.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.10.0 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/contrib v1.3.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v0.20.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.12.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0 // indirect
|
||||
go.opentelemetry.io/otel v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.7.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.16.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 // indirect
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
||||
google.golang.org/api v0.81.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
||||
google.golang.org/api v0.88.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
|
||||
google.golang.org/grpc v1.46.2 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f // indirect
|
||||
google.golang.org/grpc v1.48.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
gopkg.in/ini.v1 v1.66.6 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0 // indirect
|
||||
k8s.io/api v0.23.5 // indirect
|
||||
k8s.io/apimachinery v0.23.5 // indirect
|
||||
k8s.io/client-go v0.23.5 // indirect
|
||||
@@ -303,17 +302,17 @@ require (
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
|
||||
knative.dev/pkg v0.0.0-20220325200448-1f7514acd0c2 // indirect
|
||||
lukechampine.com/uint128 v1.1.1 // indirect
|
||||
modernc.org/cc/v3 v3.35.22 // indirect
|
||||
modernc.org/ccgo/v3 v3.15.1 // indirect
|
||||
modernc.org/libc v1.14.1 // indirect
|
||||
modernc.org/cc/v3 v3.36.0 // indirect
|
||||
modernc.org/ccgo/v3 v3.16.6 // indirect
|
||||
modernc.org/libc v1.16.7 // indirect
|
||||
modernc.org/mathutil v1.4.1 // indirect
|
||||
modernc.org/memory v1.0.5 // indirect
|
||||
modernc.org/memory v1.1.1 // indirect
|
||||
modernc.org/opt v0.1.1 // indirect
|
||||
modernc.org/sqlite v1.14.5 // indirect
|
||||
modernc.org/sqlite v1.17.3 // indirect
|
||||
modernc.org/strutil v1.1.1 // indirect
|
||||
modernc.org/token v1.0.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
sigs.k8s.io/release-utils v0.6.0 // indirect
|
||||
sigs.k8s.io/release-utils v0.7.1 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
@@ -323,5 +322,5 @@ require (
|
||||
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
||||
)
|
||||
|
||||
@@ -6,5 +6,5 @@ const (
|
||||
|
||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||
JSONSchemaVersion = "3.3.0"
|
||||
JSONSchemaVersion = "3.3.1"
|
||||
)
|
||||
|
||||
@@ -49,7 +49,7 @@ func Test_encodeLicense(t *testing.T) {
|
||||
},
|
||||
expected: &cyclonedx.Licenses{
|
||||
{License: &cyclonedx.License{ID: "MIT"}},
|
||||
{License: &cyclonedx.License{ID: "GPL-3.0"}},
|
||||
{License: &cyclonedx.License{ID: "GPL-3.0-only"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -60,7 +60,7 @@ func Test_encodeLicense(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.Licenses{
|
||||
{License: &cyclonedx.License{ID: "GPL-3.0"}},
|
||||
{License: &cyclonedx.License{ID: "GPL-3.0-only"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -71,7 +71,7 @@ func Test_encodeLicense(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.Licenses{
|
||||
{License: &cyclonedx.License{ID: "GPL-2.0"}},
|
||||
{License: &cyclonedx.License{ID: "GPL-2.0-only"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func Test_License(t *testing.T) {
|
||||
"GPL-3.0",
|
||||
},
|
||||
},
|
||||
expected: "MIT AND GPL-3.0",
|
||||
expected: "MIT AND GPL-3.0-only",
|
||||
},
|
||||
{
|
||||
name: "cap insensitive",
|
||||
@@ -53,7 +53,7 @@ func Test_License(t *testing.T) {
|
||||
"gpl-3.0",
|
||||
},
|
||||
},
|
||||
expected: "GPL-3.0",
|
||||
expected: "GPL-3.0-only",
|
||||
},
|
||||
{
|
||||
name: "debian to spdx conversion",
|
||||
@@ -62,7 +62,7 @@ func Test_License(t *testing.T) {
|
||||
"GPL-2",
|
||||
},
|
||||
},
|
||||
expected: "GPL-2.0",
|
||||
expected: "GPL-2.0-only",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
//nolint:funlen
|
||||
func SourceInfo(p pkg.Package) string {
|
||||
answer := ""
|
||||
switch p.Type {
|
||||
@@ -35,8 +36,14 @@ func SourceInfo(p pkg.Package) string {
|
||||
answer = "acquired package info from rust cargo manifest"
|
||||
case pkg.PhpComposerPkg:
|
||||
answer = "acquired package info from PHP composer manifest"
|
||||
case pkg.CocoapodsPkg:
|
||||
answer = "acquired package info from installed cocoapods manifest file"
|
||||
case pkg.ConanPkg:
|
||||
answer = "acquired package info from conan manifest"
|
||||
case pkg.PortagePkg:
|
||||
answer = "acquired package info from portage DB"
|
||||
case pkg.HackagePkg:
|
||||
answer = "acquired package info from cabal or stack manifest files"
|
||||
default:
|
||||
answer = "acquired package info from the following paths"
|
||||
}
|
||||
|
||||
@@ -150,6 +150,14 @@ func Test_SourceInfo(t *testing.T) {
|
||||
"from ALPM DB",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.CocoapodsPkg,
|
||||
},
|
||||
expected: []string{
|
||||
"installed cocoapods manifest file",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.ConanPkg,
|
||||
@@ -158,6 +166,22 @@ func Test_SourceInfo(t *testing.T) {
|
||||
"from conan manifest",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.PortagePkg,
|
||||
},
|
||||
expected: []string{
|
||||
"from portage DB",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.HackagePkg,
|
||||
},
|
||||
expected: []string{
|
||||
"from cabal or stack manifest files",
|
||||
},
|
||||
},
|
||||
}
|
||||
var pkgTypes []pkg.Type
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -145,6 +145,12 @@ func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.CocoapodsMetadataType:
|
||||
var payload pkg.CocoapodsMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.ConanaMetadataType:
|
||||
var payload pkg.ConanMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
@@ -157,6 +163,18 @@ func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.PortageMetadataType:
|
||||
var payload pkg.PortageMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.HackageMetadataType:
|
||||
var payload pkg.HackageMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
default:
|
||||
log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID)
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.3.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.0.json"
|
||||
"version": "3.3.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.3.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.0.json"
|
||||
"version": "3.3.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.3.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.0.json"
|
||||
"version": "3.3.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,18 +37,6 @@ var licenseIDs = map[string]string{
|
||||
|
||||
var versionMatch = regexp.MustCompile(`-([0-9]+)\.?([0-9]+)?\.?([0-9]+)?\.?`)
|
||||
|
||||
type LicenseList struct {
|
||||
Version string `json:"licenseListVersion"`
|
||||
Licenses []struct {
|
||||
ID string `json:"licenseId"`
|
||||
Name string `json:"name"`
|
||||
Text string `json:"licenseText"`
|
||||
Deprecated bool `json:"isDeprecatedLicenseId"`
|
||||
OSIApproved bool `json:"isOsiApproved"`
|
||||
SeeAlso []string `json:"seeAlso"`
|
||||
} `json:"licenses"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := run(); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
@@ -102,8 +90,9 @@ func run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parsing the provided SPDX license list necessitates a two pass approach.
|
||||
// The first pass is only related to what SPDX considers the truth. These K:V pairs will never be overwritten.
|
||||
// Parsing the provided SPDX license list necessitates a three pass approach.
|
||||
// The first pass is only related to what SPDX considers the truth. We use license info to
|
||||
// find replacements for deprecated licenses.
|
||||
// The second pass attempts to generate known short/long version listings for each key.
|
||||
// For info on some short name conventions see this document:
|
||||
// https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/#license-short-name.
|
||||
@@ -111,6 +100,8 @@ func run() error {
|
||||
// The new keys are then also associated with their relative SPDX value. If a key has already been entered
|
||||
// we know to ignore it since it came from the first pass which is considered the SPDX source of truth.
|
||||
// We also sort the licenses for the second pass so that cases like `GPL-1` associate to `GPL-1.0` and not `GPL-1.1`.
|
||||
// The third pass is for overwriting deprecated licenses with replacements, for example GPL-2.0+ is deprecated
|
||||
// and now maps to GPL-2.0-or-later.
|
||||
func processSPDXLicense(result LicenseList) map[string]string {
|
||||
// first pass build map
|
||||
var licenseIDs = make(map[string]string)
|
||||
@@ -122,69 +113,48 @@ func processSPDXLicense(result LicenseList) map[string]string {
|
||||
licenseIDs[cleanID] = l.ID
|
||||
}
|
||||
|
||||
// The order of variations/permutations of a license ID matters because of we how shuffle its digits,
|
||||
// that is because the permutation code can generate the same value for two difference licenses,
|
||||
// for example: The licenses `ABC-1.0` and `ABC-1.1` can both map to `ABC-1`,
|
||||
// so we need to guarantee the order they are created to avoid mapping them wrongly. So we use a sorted list.
|
||||
// To overwrite deprecated licenses during the first pass we would later on rely on map order,
|
||||
// [which in go is not consistent by design](https://stackoverflow.com/a/55925880).
|
||||
sort.Slice(result.Licenses, func(i, j int) bool {
|
||||
return result.Licenses[i].ID < result.Licenses[j].ID
|
||||
})
|
||||
|
||||
// second pass build exceptions
|
||||
// do not overwrite if already exists
|
||||
// second pass to build exceptions and replacements
|
||||
replaced := strset.New()
|
||||
for _, l := range result.Licenses {
|
||||
var multipleID []string
|
||||
cleanID := strings.ToLower(l.ID)
|
||||
|
||||
var replacement *License
|
||||
if l.Deprecated {
|
||||
replacement = result.findReplacementLicense(l)
|
||||
if replacement != nil {
|
||||
licenseIDs[cleanID] = replacement.ID
|
||||
}
|
||||
}
|
||||
|
||||
multipleID = append(multipleID, buildLicensePermutations(cleanID)...)
|
||||
for _, id := range multipleID {
|
||||
if _, exists := licenseIDs[id]; !exists {
|
||||
licenseIDs[id] = l.ID
|
||||
// don't make replacements for IDs that have already been replaced. Since we have a sorted license list
|
||||
// the earliest replacement is correct (any future replacements are not.
|
||||
// e.g. replace lgpl-2 with LGPL-2.1-only is wrong, but with LGPL-2.0-only is correct)
|
||||
if replacement == nil || replaced.Has(id) {
|
||||
if _, exists := licenseIDs[id]; !exists {
|
||||
licenseIDs[id] = l.ID
|
||||
}
|
||||
} else {
|
||||
// a useful debugging line during builds
|
||||
log.Printf("replacing %s with %s\n", id, replacement.ID)
|
||||
|
||||
licenseIDs[id] = replacement.ID
|
||||
replaced.Add(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return licenseIDs
|
||||
}
|
||||
|
||||
func buildLicensePermutations(license string) (perms []string) {
|
||||
lv := findLicenseVersion(license)
|
||||
vp := versionPermutations(lv)
|
||||
|
||||
version := strings.Join(lv, ".")
|
||||
for _, p := range vp {
|
||||
perms = append(perms, strings.Replace(license, version, p, 1))
|
||||
}
|
||||
|
||||
return perms
|
||||
}
|
||||
|
||||
func findLicenseVersion(license string) (version []string) {
|
||||
versionList := versionMatch.FindAllStringSubmatch(license, -1)
|
||||
|
||||
if len(versionList) == 0 {
|
||||
return version
|
||||
}
|
||||
|
||||
for i, v := range versionList[0] {
|
||||
if v != "" && i != 0 {
|
||||
version = append(version, v)
|
||||
}
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
func versionPermutations(version []string) []string {
|
||||
ver := append([]string(nil), version...)
|
||||
perms := strset.New()
|
||||
for i := 1; i <= 3; i++ {
|
||||
if len(ver) < i+1 {
|
||||
ver = append(ver, "0")
|
||||
}
|
||||
|
||||
perm := strings.Join(ver[:i], ".")
|
||||
badCount := strings.Count(perm, "0") + strings.Count(perm, ".")
|
||||
|
||||
if badCount != len(perm) {
|
||||
perms.Add(perm)
|
||||
}
|
||||
}
|
||||
|
||||
return perms.List()
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,104 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
)
|
||||
|
||||
type LicenseList struct {
|
||||
Version string `json:"licenseListVersion"`
|
||||
Licenses []License `json:"licenses"`
|
||||
}
|
||||
|
||||
type License struct {
|
||||
ID string `json:"licenseId"`
|
||||
Name string `json:"name"`
|
||||
Text string `json:"licenseText"`
|
||||
Deprecated bool `json:"isDeprecatedLicenseId"`
|
||||
OSIApproved bool `json:"isOsiApproved"`
|
||||
SeeAlso []string `json:"seeAlso"`
|
||||
}
|
||||
|
||||
func (l License) canReplace(other License) bool {
|
||||
if l.Deprecated {
|
||||
return false
|
||||
}
|
||||
|
||||
if l.Name != other.Name {
|
||||
return false
|
||||
}
|
||||
|
||||
if l.OSIApproved != other.OSIApproved {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(l.SeeAlso) != len(other.SeeAlso) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, sa := range l.SeeAlso {
|
||||
if sa != other.SeeAlso[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return l.ID != other.ID
|
||||
}
|
||||
|
||||
func (ll LicenseList) findReplacementLicense(deprecated License) *License {
|
||||
for _, l := range ll.Licenses {
|
||||
if l.canReplace(deprecated) {
|
||||
return &l
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildLicensePermutations(license string) (perms []string) {
|
||||
lv := findLicenseVersion(license)
|
||||
vp := versionPermutations(lv)
|
||||
|
||||
version := strings.Join(lv, ".")
|
||||
for _, p := range vp {
|
||||
perms = append(perms, strings.Replace(license, version, p, 1))
|
||||
}
|
||||
|
||||
return perms
|
||||
}
|
||||
|
||||
func findLicenseVersion(license string) (version []string) {
|
||||
versionList := versionMatch.FindAllStringSubmatch(license, -1)
|
||||
|
||||
if len(versionList) == 0 {
|
||||
return version
|
||||
}
|
||||
|
||||
for i, v := range versionList[0] {
|
||||
if v != "" && i != 0 {
|
||||
version = append(version, v)
|
||||
}
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
func versionPermutations(version []string) []string {
|
||||
ver := append([]string(nil), version...)
|
||||
perms := strset.New()
|
||||
for i := 1; i <= 3; i++ {
|
||||
if len(ver) < i+1 {
|
||||
ver = append(ver, "0")
|
||||
}
|
||||
|
||||
perm := strings.Join(ver[:i], ".")
|
||||
badCount := strings.Count(perm, "0") + strings.Count(perm, ".")
|
||||
|
||||
if badCount != len(perm) {
|
||||
perms.Add(perm)
|
||||
}
|
||||
}
|
||||
|
||||
return perms.List()
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
license1 = License{
|
||||
ID: "ABC-1.0+",
|
||||
Name: "The ABC License 1.0",
|
||||
Deprecated: true,
|
||||
}
|
||||
|
||||
license2 = License{
|
||||
ID: "ABC-1.0-Or-later",
|
||||
Name: "The ABC License 1.0",
|
||||
}
|
||||
|
||||
license3 = License{
|
||||
ID: "ABC-1.0",
|
||||
Name: "The ABC License 1.0 Only",
|
||||
Deprecated: true,
|
||||
}
|
||||
|
||||
license4 = License{
|
||||
ID: "ABC-1.0-Only",
|
||||
Name: "The ABC License 1.0 Only",
|
||||
}
|
||||
license5 = License{
|
||||
ID: "Duh-1.0",
|
||||
Name: "The Duh License 1.0",
|
||||
Deprecated: true,
|
||||
}
|
||||
license6 = License{
|
||||
ID: "Duh-1.0-duh",
|
||||
Name: "The Duh License 1.0",
|
||||
Deprecated: true,
|
||||
}
|
||||
)
|
||||
|
||||
func TestLicense_canReplace(t *testing.T) {
|
||||
tests := []struct {
|
||||
l1, l2 License
|
||||
expected bool
|
||||
}{
|
||||
{license1, license2, false},
|
||||
{license2, license1, true},
|
||||
{license2, license3, false},
|
||||
{license3, license2, false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(t, tt.expected, tt.l1.canReplace(tt.l2))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLicensePermutations(t *testing.T) {
|
||||
var tests = []struct {
|
||||
shortName string
|
||||
permutations []string
|
||||
}{
|
||||
{
|
||||
"GPL-1-only",
|
||||
[]string{
|
||||
"GPL-1-only",
|
||||
"GPL-1.0-only",
|
||||
"GPL-1.0.0-only",
|
||||
},
|
||||
},
|
||||
{
|
||||
"GPL-2",
|
||||
[]string{
|
||||
"GPL-2",
|
||||
"GPL-2.0",
|
||||
"GPL-2.0.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"GPL-2.0+",
|
||||
[]string{
|
||||
"GPL-2+",
|
||||
"GPL-2.0+",
|
||||
"GPL-2.0.0+",
|
||||
},
|
||||
},
|
||||
{
|
||||
"GPL-3.0.0-or-later",
|
||||
[]string{
|
||||
"GPL-3-or-later",
|
||||
"GPL-3.0-or-later",
|
||||
"GPL-3.0.0-or-later",
|
||||
},
|
||||
},
|
||||
{
|
||||
"abc-1.1",
|
||||
[]string{
|
||||
"abc-1",
|
||||
"abc-1.1",
|
||||
"abc-1.1.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"oldap-2.0",
|
||||
[]string{
|
||||
"oldap-2",
|
||||
"oldap-2.0",
|
||||
"oldap-2.0.0",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.shortName, func(t *testing.T) {
|
||||
perms := buildLicensePermutations(test.shortName)
|
||||
assert.ElementsMatch(t, test.permutations, perms)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionPermutations(t *testing.T) {
|
||||
var tests = []struct {
|
||||
version []string
|
||||
permutations []string
|
||||
}{
|
||||
{
|
||||
[]string{"1", "0"},
|
||||
[]string{"1", "1.0", "1.0.0"},
|
||||
},
|
||||
{
|
||||
[]string{"2"},
|
||||
[]string{"2", "2.0", "2.0.0"},
|
||||
},
|
||||
{
|
||||
[]string{"2", "0"},
|
||||
[]string{"2", "2.0", "2.0.0"},
|
||||
},
|
||||
|
||||
{
|
||||
[]string{"3", "0", "0"},
|
||||
[]string{"3", "3.0", "3.0.0"},
|
||||
},
|
||||
{
|
||||
[]string{"0", "3"},
|
||||
[]string{"0.3", "0.3.0"},
|
||||
},
|
||||
{
|
||||
[]string{"0", "0", "3"},
|
||||
[]string{"0.0.3"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(strings.Join(test.version, "."), func(t *testing.T) {
|
||||
got := versionPermutations(test.version)
|
||||
assert.ElementsMatch(t, test.permutations, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindLicenseVersion(t *testing.T) {
|
||||
var tests = []struct {
|
||||
license string
|
||||
version []string
|
||||
}{
|
||||
{
|
||||
"GPL-1.0-only",
|
||||
[]string{"1", "0"},
|
||||
},
|
||||
{
|
||||
"GPL-2.0",
|
||||
[]string{"2", "0"},
|
||||
},
|
||||
{
|
||||
"GPL-2.0.0",
|
||||
[]string{"2", "0", "0"},
|
||||
},
|
||||
{
|
||||
"GPL-2",
|
||||
[]string{"2"},
|
||||
},
|
||||
{
|
||||
"bzip2-1",
|
||||
[]string{"1"},
|
||||
},
|
||||
{
|
||||
"php-3.01",
|
||||
[]string{"3", "01"},
|
||||
},
|
||||
{
|
||||
"oldap-2.0",
|
||||
[]string{"2", "0"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.license, func(t *testing.T) {
|
||||
got := findLicenseVersion(test.license)
|
||||
assert.Equal(t, test.version, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_findReplacementLicense(t *testing.T) {
|
||||
tests := []struct {
|
||||
l License
|
||||
expected *License
|
||||
licenses LicenseList
|
||||
}{
|
||||
{license1, nil, LicenseList{}},
|
||||
{license1, nil, LicenseList{Licenses: []License{license3}}},
|
||||
{license1, &license2, LicenseList{Licenses: []License{license2, license3}}},
|
||||
{license1, &license2, LicenseList{Licenses: []License{license2, license3, license4, license5}}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
assert.Equal(t, tt.expected, tt.licenses.findReplacementLicense(tt.l))
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at 2022-05-09 10:01:37.625063 -0400 EDT m=+0.423632834
|
||||
// This file was generated by robots at 2022-08-02 12:46:45.90647 -0400 EDT m=+0.327870639
|
||||
// using data from https://spdx.org/licenses/licenses.json
|
||||
package spdxlicense
|
||||
|
||||
@@ -524,20 +524,20 @@ var licenseIDs = map[string]string{
|
||||
"glulxe": "Glulxe",
|
||||
"glwtpl": "GLWTPL",
|
||||
"gnuplot": "gnuplot",
|
||||
"gpl-1": "GPL-1.0",
|
||||
"gpl-1+": "GPL-1.0+",
|
||||
"gpl-1": "GPL-1.0-only",
|
||||
"gpl-1+": "GPL-1.0-or-later",
|
||||
"gpl-1-only": "GPL-1.0-only",
|
||||
"gpl-1-or-later": "GPL-1.0-or-later",
|
||||
"gpl-1.0": "GPL-1.0",
|
||||
"gpl-1.0+": "GPL-1.0+",
|
||||
"gpl-1.0": "GPL-1.0-only",
|
||||
"gpl-1.0+": "GPL-1.0-or-later",
|
||||
"gpl-1.0-only": "GPL-1.0-only",
|
||||
"gpl-1.0-or-later": "GPL-1.0-or-later",
|
||||
"gpl-1.0.0": "GPL-1.0",
|
||||
"gpl-1.0.0+": "GPL-1.0+",
|
||||
"gpl-1.0.0": "GPL-1.0-only",
|
||||
"gpl-1.0.0+": "GPL-1.0-or-later",
|
||||
"gpl-1.0.0-only": "GPL-1.0-only",
|
||||
"gpl-1.0.0-or-later": "GPL-1.0-or-later",
|
||||
"gpl-2": "GPL-2.0",
|
||||
"gpl-2+": "GPL-2.0+",
|
||||
"gpl-2": "GPL-2.0-only",
|
||||
"gpl-2+": "GPL-2.0-or-later",
|
||||
"gpl-2-only": "GPL-2.0-only",
|
||||
"gpl-2-or-later": "GPL-2.0-or-later",
|
||||
"gpl-2-with-autoconf-exception": "GPL-2.0-with-autoconf-exception",
|
||||
@@ -545,8 +545,8 @@ var licenseIDs = map[string]string{
|
||||
"gpl-2-with-classpath-exception": "GPL-2.0-with-classpath-exception",
|
||||
"gpl-2-with-font-exception": "GPL-2.0-with-font-exception",
|
||||
"gpl-2-with-gcc-exception": "GPL-2.0-with-GCC-exception",
|
||||
"gpl-2.0": "GPL-2.0",
|
||||
"gpl-2.0+": "GPL-2.0+",
|
||||
"gpl-2.0": "GPL-2.0-only",
|
||||
"gpl-2.0+": "GPL-2.0-or-later",
|
||||
"gpl-2.0-only": "GPL-2.0-only",
|
||||
"gpl-2.0-or-later": "GPL-2.0-or-later",
|
||||
"gpl-2.0-with-autoconf-exception": "GPL-2.0-with-autoconf-exception",
|
||||
@@ -554,8 +554,8 @@ var licenseIDs = map[string]string{
|
||||
"gpl-2.0-with-classpath-exception": "GPL-2.0-with-classpath-exception",
|
||||
"gpl-2.0-with-font-exception": "GPL-2.0-with-font-exception",
|
||||
"gpl-2.0-with-gcc-exception": "GPL-2.0-with-GCC-exception",
|
||||
"gpl-2.0.0": "GPL-2.0",
|
||||
"gpl-2.0.0+": "GPL-2.0+",
|
||||
"gpl-2.0.0": "GPL-2.0-only",
|
||||
"gpl-2.0.0+": "GPL-2.0-or-later",
|
||||
"gpl-2.0.0-only": "GPL-2.0-only",
|
||||
"gpl-2.0.0-or-later": "GPL-2.0-or-later",
|
||||
"gpl-2.0.0-with-autoconf-exception": "GPL-2.0-with-autoconf-exception",
|
||||
@@ -563,20 +563,20 @@ var licenseIDs = map[string]string{
|
||||
"gpl-2.0.0-with-classpath-exception": "GPL-2.0-with-classpath-exception",
|
||||
"gpl-2.0.0-with-font-exception": "GPL-2.0-with-font-exception",
|
||||
"gpl-2.0.0-with-gcc-exception": "GPL-2.0-with-GCC-exception",
|
||||
"gpl-3": "GPL-3.0",
|
||||
"gpl-3+": "GPL-3.0+",
|
||||
"gpl-3": "GPL-3.0-only",
|
||||
"gpl-3+": "GPL-3.0-or-later",
|
||||
"gpl-3-only": "GPL-3.0-only",
|
||||
"gpl-3-or-later": "GPL-3.0-or-later",
|
||||
"gpl-3-with-autoconf-exception": "GPL-3.0-with-autoconf-exception",
|
||||
"gpl-3-with-gcc-exception": "GPL-3.0-with-GCC-exception",
|
||||
"gpl-3.0": "GPL-3.0",
|
||||
"gpl-3.0+": "GPL-3.0+",
|
||||
"gpl-3.0": "GPL-3.0-only",
|
||||
"gpl-3.0+": "GPL-3.0-or-later",
|
||||
"gpl-3.0-only": "GPL-3.0-only",
|
||||
"gpl-3.0-or-later": "GPL-3.0-or-later",
|
||||
"gpl-3.0-with-autoconf-exception": "GPL-3.0-with-autoconf-exception",
|
||||
"gpl-3.0-with-gcc-exception": "GPL-3.0-with-GCC-exception",
|
||||
"gpl-3.0.0": "GPL-3.0",
|
||||
"gpl-3.0.0+": "GPL-3.0+",
|
||||
"gpl-3.0.0": "GPL-3.0-only",
|
||||
"gpl-3.0.0+": "GPL-3.0-or-later",
|
||||
"gpl-3.0.0-only": "GPL-3.0-only",
|
||||
"gpl-3.0.0-or-later": "GPL-3.0-or-later",
|
||||
"gpl-3.0.0-with-autoconf-exception": "GPL-3.0-with-autoconf-exception",
|
||||
@@ -622,36 +622,36 @@ var licenseIDs = map[string]string{
|
||||
"lal-1.3.0": "LAL-1.3",
|
||||
"latex2e": "Latex2e",
|
||||
"leptonica": "Leptonica",
|
||||
"lgpl-2": "LGPL-2.0",
|
||||
"lgpl-2+": "LGPL-2.0+",
|
||||
"lgpl-2": "LGPL-2.1-only",
|
||||
"lgpl-2+": "LGPL-2.0-or-later",
|
||||
"lgpl-2-only": "LGPL-2.0-only",
|
||||
"lgpl-2-or-later": "LGPL-2.0-or-later",
|
||||
"lgpl-2.0": "LGPL-2.0",
|
||||
"lgpl-2.0+": "LGPL-2.0+",
|
||||
"lgpl-2.0": "LGPL-2.0-only",
|
||||
"lgpl-2.0+": "LGPL-2.0-or-later",
|
||||
"lgpl-2.0-only": "LGPL-2.0-only",
|
||||
"lgpl-2.0-or-later": "LGPL-2.0-or-later",
|
||||
"lgpl-2.0.0": "LGPL-2.0",
|
||||
"lgpl-2.0.0+": "LGPL-2.0+",
|
||||
"lgpl-2.0.0": "LGPL-2.0-only",
|
||||
"lgpl-2.0.0+": "LGPL-2.0-or-later",
|
||||
"lgpl-2.0.0-only": "LGPL-2.0-only",
|
||||
"lgpl-2.0.0-or-later": "LGPL-2.0-or-later",
|
||||
"lgpl-2.1": "LGPL-2.1",
|
||||
"lgpl-2.1": "LGPL-2.1-only",
|
||||
"lgpl-2.1+": "LGPL-2.1+",
|
||||
"lgpl-2.1-only": "LGPL-2.1-only",
|
||||
"lgpl-2.1-or-later": "LGPL-2.1-or-later",
|
||||
"lgpl-2.1.0": "LGPL-2.1",
|
||||
"lgpl-2.1.0": "LGPL-2.1-only",
|
||||
"lgpl-2.1.0+": "LGPL-2.1+",
|
||||
"lgpl-2.1.0-only": "LGPL-2.1-only",
|
||||
"lgpl-2.1.0-or-later": "LGPL-2.1-or-later",
|
||||
"lgpl-3": "LGPL-3.0",
|
||||
"lgpl-3+": "LGPL-3.0+",
|
||||
"lgpl-3": "LGPL-3.0-only",
|
||||
"lgpl-3+": "LGPL-3.0-or-later",
|
||||
"lgpl-3-only": "LGPL-3.0-only",
|
||||
"lgpl-3-or-later": "LGPL-3.0-or-later",
|
||||
"lgpl-3.0": "LGPL-3.0",
|
||||
"lgpl-3.0+": "LGPL-3.0+",
|
||||
"lgpl-3.0": "LGPL-3.0-only",
|
||||
"lgpl-3.0+": "LGPL-3.0-or-later",
|
||||
"lgpl-3.0-only": "LGPL-3.0-only",
|
||||
"lgpl-3.0-or-later": "LGPL-3.0-or-later",
|
||||
"lgpl-3.0.0": "LGPL-3.0",
|
||||
"lgpl-3.0.0+": "LGPL-3.0+",
|
||||
"lgpl-3.0.0": "LGPL-3.0-only",
|
||||
"lgpl-3.0.0+": "LGPL-3.0-or-later",
|
||||
"lgpl-3.0.0-only": "LGPL-3.0-only",
|
||||
"lgpl-3.0.0-or-later": "LGPL-3.0-or-later",
|
||||
"lgpllr": "LGPLLR",
|
||||
|
||||
@@ -10,6 +10,7 @@ func TestLicenceListIDs(t *testing.T) {
|
||||
// do a sanity check on the generated data
|
||||
assert.Equal(t, "0BSD", licenseIDs["0bsd"])
|
||||
assert.Equal(t, "ZPL-2.1", licenseIDs["zpl-2.1"])
|
||||
assert.Equal(t, "GPL-2.0", licenseIDs["gpl-2"])
|
||||
assert.Equal(t, "GPL-2.0-only", licenseIDs["gpl-2"])
|
||||
assert.Equal(t, "GPL-2.0-or-later", licenseIDs["gpl-2+"])
|
||||
assert.NotEmpty(t, Version)
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ func TestIDParse(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"GPL-2",
|
||||
"GPL-2.0",
|
||||
"GPL-2.0-only",
|
||||
},
|
||||
{
|
||||
"GPL-2+",
|
||||
"GPL-2.0+",
|
||||
"GPL-2.0-or-later",
|
||||
},
|
||||
{
|
||||
"GPL-3.0.0-or-later",
|
||||
|
||||
@@ -25,7 +25,7 @@ Given a version number format `MODEL.REVISION.ADDITION`:
|
||||
When adding a new `pkg.*Metadata` that is assigned to the `pkg.Package.Metadata` struct field it is important that a few things
|
||||
are done:
|
||||
|
||||
- a new integration test case is added to `test/integration/pkg_cases_test.go` that exercises the new package type with the new metadata
|
||||
- a new integration test case is added to `test/integration/catalog_packages_cases_test.go` that exercises the new package type with the new metadata
|
||||
- the new metadata struct is added to the `artifactMetadataContainer` struct within `schema/json/generate.go`
|
||||
|
||||
## Generating a New Schema
|
||||
@@ -36,4 +36,4 @@ Create the new schema by running `cd schema/json && go run generate.go` (note yo
|
||||
- If there is an existing schema for the given version and the new schema matches the existing schema, no action is taken
|
||||
- If there is an existing schema for the given version and the new schema **does not** match the existing schema, an error is shown indicating to increment the version appropriately (see the "Versioning" section)
|
||||
|
||||
***Note: never delete a JSON schema and never change an existing JSON schema once it has been published in a release!*** Only add new schemas with a newly incremented version. All previous schema files must be stored in the `schema/json/` directory.
|
||||
***Note: never delete a JSON schema and never change an existing JSON schema once it has been published in a release!*** Only add new schemas with a newly incremented version. All previous schema files must be stored in the `schema/json/` directory.
|
||||
|
||||
+14
-13
@@ -27,19 +27,20 @@ can be extended to include specific package metadata struct shapes in the future
|
||||
// When a new package metadata definition is created it will need to be manually added here. The variable name does
|
||||
// not matter as long as it is exported.
|
||||
type artifactMetadataContainer struct {
|
||||
Apk pkg.ApkMetadata
|
||||
Alpm pkg.AlpmMetadata
|
||||
Dpkg pkg.DpkgMetadata
|
||||
Gem pkg.GemMetadata
|
||||
Java pkg.JavaMetadata
|
||||
Npm pkg.NpmPackageJSONMetadata
|
||||
Python pkg.PythonPackageMetadata
|
||||
Rpm pkg.RpmdbMetadata
|
||||
Cargo pkg.CargoPackageMetadata
|
||||
Go pkg.GolangBinMetadata
|
||||
Php pkg.PhpComposerJSONMetadata
|
||||
Dart pkg.DartPubMetadata
|
||||
Dotnet pkg.DotnetDepsMetadata
|
||||
Apk pkg.ApkMetadata
|
||||
Alpm pkg.AlpmMetadata
|
||||
Dpkg pkg.DpkgMetadata
|
||||
Gem pkg.GemMetadata
|
||||
Java pkg.JavaMetadata
|
||||
Npm pkg.NpmPackageJSONMetadata
|
||||
Python pkg.PythonPackageMetadata
|
||||
Rpm pkg.RpmdbMetadata
|
||||
Cargo pkg.CargoPackageMetadata
|
||||
Go pkg.GolangBinMetadata
|
||||
Php pkg.PhpComposerJSONMetadata
|
||||
Dart pkg.DartPubMetadata
|
||||
Dotnet pkg.DotnetDepsMetadata
|
||||
Portage pkg.PortageMetadata
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,13 +18,16 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/deb"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/dotnet"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/golang"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/haskell"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/php"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/portage"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/python"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/rpmdb"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/ruby"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/rust"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/swift"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
@@ -54,6 +57,7 @@ func ImageCatalogers(cfg Config) []Cataloger {
|
||||
apkdb.NewApkdbCataloger(),
|
||||
golang.NewGoModuleBinaryCataloger(),
|
||||
dotnet.NewDotnetDepsCataloger(),
|
||||
portage.NewPortageCataloger(),
|
||||
}, cfg.Catalogers)
|
||||
}
|
||||
|
||||
@@ -76,7 +80,10 @@ func DirectoryCatalogers(cfg Config) []Cataloger {
|
||||
rust.NewCargoLockCataloger(),
|
||||
dart.NewPubspecLockCataloger(),
|
||||
dotnet.NewDotnetDepsCataloger(),
|
||||
swift.NewCocoapodsCataloger(),
|
||||
cpp.NewConanfileCataloger(),
|
||||
portage.NewPortageCataloger(),
|
||||
haskell.NewHackageCataloger(),
|
||||
}, cfg.Catalogers)
|
||||
}
|
||||
|
||||
@@ -98,11 +105,15 @@ func AllCatalogers(cfg Config) []Cataloger {
|
||||
golang.NewGoModuleBinaryCataloger(),
|
||||
golang.NewGoModFileCataloger(),
|
||||
rust.NewCargoLockCataloger(),
|
||||
rust.NewRustAuditBinaryCataloger(),
|
||||
dart.NewPubspecLockCataloger(),
|
||||
dotnet.NewDotnetDepsCataloger(),
|
||||
php.NewPHPComposerInstalledCataloger(),
|
||||
php.NewPHPComposerLockCataloger(),
|
||||
swift.NewCocoapodsCataloger(),
|
||||
cpp.NewConanfileCataloger(),
|
||||
portage.NewPortageCataloger(),
|
||||
haskell.NewHackageCataloger(),
|
||||
}, cfg.Catalogers)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,13 @@ Package golang provides a concrete Cataloger implementation for go.mod files.
|
||||
package golang
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
@@ -46,7 +44,7 @@ func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []arti
|
||||
continue
|
||||
}
|
||||
|
||||
reader, err := getUnionReader(readerCloser)
|
||||
reader, err := unionreader.GetUnionReader(readerCloser)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -61,30 +59,3 @@ func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []arti
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
func getUnionReader(readerCloser io.ReadCloser) (unionReader, error) {
|
||||
reader, ok := readerCloser.(unionReader)
|
||||
if ok {
|
||||
return reader, nil
|
||||
}
|
||||
log.Debugf("golang cataloger: unable to use stereoscope file, reading entire contents")
|
||||
|
||||
b, err := ioutil.ReadAll(readerCloser)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read contents from go binary: %w", err)
|
||||
}
|
||||
|
||||
bytesReader := bytes.NewReader(b)
|
||||
|
||||
reader = struct {
|
||||
io.ReadCloser
|
||||
io.ReaderAt
|
||||
io.Seeker
|
||||
}{
|
||||
ReadCloser: io.NopCloser(bytesReader),
|
||||
ReaderAt: bytesReader,
|
||||
Seeker: bytesReader,
|
||||
}
|
||||
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
@@ -2,27 +2,17 @@ package golang
|
||||
|
||||
import (
|
||||
"debug/buildinfo"
|
||||
"io"
|
||||
"runtime/debug"
|
||||
|
||||
macho "github.com/anchore/go-macholibre"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
|
||||
)
|
||||
|
||||
// unionReader is a single interface with all reading functions used by golang bin
|
||||
// cataloger.
|
||||
type unionReader interface {
|
||||
io.Reader
|
||||
io.ReaderAt
|
||||
io.Seeker
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// scanFile scans file to try to report the Go and module versions.
|
||||
func scanFile(reader unionReader, filename string) ([]*debug.BuildInfo, []string) {
|
||||
func scanFile(reader unionreader.UnionReader, filename string) ([]*debug.BuildInfo, []string) {
|
||||
// NOTE: multiple readers are returned to cover universal binaries, which are files
|
||||
// with more than one binary
|
||||
readers, err := getReaders(reader)
|
||||
readers, err := unionreader.GetReaders(reader)
|
||||
if err != nil {
|
||||
log.Warnf("golang cataloger: failed to open a binary: %v", err)
|
||||
return nil, nil
|
||||
@@ -56,23 +46,3 @@ func scanFile(reader unionReader, filename string) ([]*debug.BuildInfo, []string
|
||||
|
||||
return builds, archs
|
||||
}
|
||||
|
||||
// getReaders extracts one or more io.ReaderAt objects representing binaries that can be processed (multiple binaries in the case for multi-architecture binaries).
|
||||
func getReaders(f unionReader) ([]io.ReaderAt, error) {
|
||||
if macho.IsUniversalMachoBinary(f) {
|
||||
machoReaders, err := macho.ExtractReaders(f)
|
||||
if err != nil {
|
||||
log.Debugf("extracting readers: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var readers []io.ReaderAt
|
||||
for _, e := range machoReaders {
|
||||
readers = append(readers, e.Reader)
|
||||
}
|
||||
|
||||
return readers, nil
|
||||
}
|
||||
|
||||
return []io.ReaderAt{f}, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package haskell
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||
)
|
||||
|
||||
// NewHackageCataloger returns a new Haskell cataloger object.
|
||||
func NewHackageCataloger() *common.GenericCataloger {
|
||||
globParsers := map[string]common.ParserFn{
|
||||
"**/stack.yaml": parseStackYaml,
|
||||
"**/stack.yaml.lock": parseStackLock,
|
||||
"**/cabal.project.freeze": parseCabalFreeze,
|
||||
}
|
||||
return common.NewGenericCataloger(nil, globParsers, "hackage-cataloger")
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package haskell
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ common.ParserFn = parseCabalFreeze
|
||||
|
||||
// parseCabalFreeze is a parser function for cabal.project.freeze contents, returning all packages discovered.
|
||||
func parseCabalFreeze(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||
r := bufio.NewReader(reader)
|
||||
pkgs := []*pkg.Package{}
|
||||
for {
|
||||
line, err := r.ReadString('\n')
|
||||
switch {
|
||||
case errors.Is(io.EOF, err):
|
||||
return pkgs, nil, nil
|
||||
case err != nil:
|
||||
return nil, nil, fmt.Errorf("failed to parse cabal.project.freeze file: %w", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(line, "any.") {
|
||||
continue
|
||||
}
|
||||
|
||||
line = strings.TrimSpace(line)
|
||||
startPkgEncoding, endPkgEncoding := strings.Index(line, "any.")+4, strings.Index(line, ",")
|
||||
line = line[startPkgEncoding:endPkgEncoding]
|
||||
splits := strings.Split(line, " ==")
|
||||
|
||||
pkgName, pkgVersion := splits[0], splits[1]
|
||||
pkgs = append(pkgs, &pkg.Package{
|
||||
Name: pkgName,
|
||||
Version: pkgVersion,
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: pkgName,
|
||||
Version: pkgVersion,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package haskell
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func TestParseCabalFreeze(t *testing.T) {
|
||||
expected := []*pkg.Package{
|
||||
{
|
||||
Name: "Cabal",
|
||||
Version: "3.2.1.0",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "Cabal",
|
||||
Version: "3.2.1.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Diff",
|
||||
Version: "0.4.1",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "Diff",
|
||||
Version: "0.4.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "HTTP",
|
||||
Version: "4000.3.16",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "HTTP",
|
||||
Version: "4000.3.16",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "HUnit",
|
||||
Version: "1.6.2.0",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "HUnit",
|
||||
Version: "1.6.2.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "OneTuple",
|
||||
Version: "0.3.1",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "OneTuple",
|
||||
Version: "0.3.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Only",
|
||||
Version: "0.1",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "Only",
|
||||
Version: "0.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PyF",
|
||||
Version: "0.10.2.0",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "PyF",
|
||||
Version: "0.10.2.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "QuickCheck",
|
||||
Version: "2.14.2",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "QuickCheck",
|
||||
Version: "2.14.2",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "RSA",
|
||||
Version: "2.4.1",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "RSA",
|
||||
Version: "2.4.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "SHA",
|
||||
Version: "1.6.4.4",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "SHA",
|
||||
Version: "1.6.4.4",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Spock",
|
||||
Version: "0.14.0.0",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "Spock",
|
||||
Version: "0.14.0.0",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fixture, err := os.Open("test-fixtures/cabal.project.freeze")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
}
|
||||
|
||||
// TODO: no relationships are under test yet
|
||||
actual, _, err := parseCabalFreeze(fixture.Name(), fixture)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
differences := deep.Equal(expected, actual)
|
||||
if differences != nil {
|
||||
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package haskell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ common.ParserFn = parseStackLock
|
||||
|
||||
type stackLock struct {
|
||||
Packages []stackPackage `yaml:"packages"`
|
||||
Snapshots []stackSnapshot `yaml:"snapshots"`
|
||||
}
|
||||
|
||||
type stackPackage struct {
|
||||
Completed completedPackage `yaml:"completed"`
|
||||
}
|
||||
|
||||
type completedPackage struct {
|
||||
Hackage string `yaml:"hackage"`
|
||||
}
|
||||
|
||||
type stackSnapshot struct {
|
||||
Completed completedSnapshot `yaml:"completed"`
|
||||
}
|
||||
|
||||
type completedSnapshot struct {
|
||||
URL string `yaml:"url"`
|
||||
Sha string `yaml:"sha256"`
|
||||
}
|
||||
|
||||
func parseStackPackageEncoding(pkgEncoding string) (name, version, hash string) {
|
||||
lastDashIdx := strings.LastIndex(pkgEncoding, "-")
|
||||
name = pkgEncoding[:lastDashIdx]
|
||||
remainingEncoding := pkgEncoding[lastDashIdx+1:]
|
||||
encodingSplits := strings.Split(remainingEncoding, "@")
|
||||
version = encodingSplits[0]
|
||||
startHash, endHash := strings.Index(encodingSplits[1], ":")+1, strings.Index(encodingSplits[1], ",")
|
||||
hash = encodingSplits[1][startHash:endHash]
|
||||
return
|
||||
}
|
||||
|
||||
// parseStackLock is a parser function for stack.yaml.lock contents, returning all packages discovered.
|
||||
func parseStackLock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||
bytes, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to load stack.yaml.lock file: %w", err)
|
||||
}
|
||||
|
||||
var lockFile stackLock
|
||||
|
||||
if err := yaml.Unmarshal(bytes, &lockFile); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse stack.yaml.lock file: %w", err)
|
||||
}
|
||||
|
||||
var (
|
||||
pkgs []*pkg.Package
|
||||
snapshotURL string
|
||||
)
|
||||
|
||||
for _, snap := range lockFile.Snapshots {
|
||||
snapshotURL = snap.Completed.URL
|
||||
}
|
||||
|
||||
for _, pack := range lockFile.Packages {
|
||||
pkgName, pkgVersion, pkgHash := parseStackPackageEncoding(pack.Completed.Hackage)
|
||||
pkgs = append(pkgs, &pkg.Package{
|
||||
Name: pkgName,
|
||||
Version: pkgVersion,
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: pkgName,
|
||||
Version: pkgVersion,
|
||||
PkgHash: &pkgHash,
|
||||
SnapshotURL: &snapshotURL,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package haskell
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func fixtureP(str string) *string {
|
||||
return &str
|
||||
}
|
||||
|
||||
func TestParseStackLock(t *testing.T) {
|
||||
url := "https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/14.yaml"
|
||||
expected := []*pkg.Package{
|
||||
{
|
||||
Name: "HTTP",
|
||||
Version: "4000.3.16",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "HTTP",
|
||||
Version: "4000.3.16",
|
||||
PkgHash: fixtureP("6042643c15a0b43e522a6693f1e322f05000d519543a84149cb80aeffee34f71"),
|
||||
SnapshotURL: &url,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "configurator-pg",
|
||||
Version: "0.2.6",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "configurator-pg",
|
||||
Version: "0.2.6",
|
||||
PkgHash: fixtureP("cd9b06a458428e493a4d6def725af7ab1ab0fef678fbd871f9586fc7f9aa70be"),
|
||||
SnapshotURL: &url,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "hasql-dynamic-statements",
|
||||
Version: "0.3.1.1",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "hasql-dynamic-statements",
|
||||
Version: "0.3.1.1",
|
||||
PkgHash: fixtureP("2cfe6e75990e690f595a87cbe553f2e90fcd738610f6c66749c81cc4396b2cc4"),
|
||||
SnapshotURL: &url,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "hasql-implicits",
|
||||
Version: "0.1.0.4",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "hasql-implicits",
|
||||
Version: "0.1.0.4",
|
||||
PkgHash: fixtureP("0848d3cbc9d94e1e539948fa0be4d0326b26335034161bf8076785293444ca6f"),
|
||||
SnapshotURL: &url,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "hasql-pool",
|
||||
Version: "0.5.2.2",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "hasql-pool",
|
||||
Version: "0.5.2.2",
|
||||
PkgHash: fixtureP("b56d4dea112d97a2ef4b2749508c0ca646828cb2d77b827e8dc433d249bb2062"),
|
||||
SnapshotURL: &url,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "lens-aeson",
|
||||
Version: "1.1.3",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "lens-aeson",
|
||||
Version: "1.1.3",
|
||||
PkgHash: fixtureP("52c8eaecd2d1c2a969c0762277c4a8ee72c339a686727d5785932e72ef9c3050"),
|
||||
SnapshotURL: &url,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "optparse-applicative",
|
||||
Version: "0.16.1.0",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "optparse-applicative",
|
||||
Version: "0.16.1.0",
|
||||
PkgHash: fixtureP("418c22ed6a19124d457d96bc66bd22c93ac22fad0c7100fe4972bbb4ac989731"),
|
||||
SnapshotURL: &url,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "protolude",
|
||||
Version: "0.3.2",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "protolude",
|
||||
Version: "0.3.2",
|
||||
PkgHash: fixtureP("2a38b3dad40d238ab644e234b692c8911423f9d3ed0e36b62287c4a698d92cd1"),
|
||||
SnapshotURL: &url,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ptr",
|
||||
Version: "0.16.8.2",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "ptr",
|
||||
Version: "0.16.8.2",
|
||||
PkgHash: fixtureP("708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac"),
|
||||
SnapshotURL: &url,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fixture, err := os.Open("test-fixtures/stack.yaml.lock")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
}
|
||||
|
||||
// TODO: no relationships are under test yet
|
||||
actual, _, err := parseStackLock(fixture.Name(), fixture)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
differences := deep.Equal(expected, actual)
|
||||
if differences != nil {
|
||||
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package haskell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ common.ParserFn = parseStackYaml
|
||||
|
||||
type stackYaml struct {
|
||||
ExtraDeps []string `yaml:"extra-deps"`
|
||||
}
|
||||
|
||||
// parseStackYaml is a parser function for stack.yaml contents, returning all packages discovered.
|
||||
func parseStackYaml(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||
bytes, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to load stack.yaml file: %w", err)
|
||||
}
|
||||
|
||||
var stackFile stackYaml
|
||||
|
||||
if err := yaml.Unmarshal(bytes, &stackFile); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse stack.yaml file: %w", err)
|
||||
}
|
||||
|
||||
var (
|
||||
pkgs []*pkg.Package
|
||||
)
|
||||
|
||||
for _, dep := range stackFile.ExtraDeps {
|
||||
pkgName, pkgVersion, pkgHash := parseStackPackageEncoding(dep)
|
||||
pkgs = append(pkgs, &pkg.Package{
|
||||
Name: pkgName,
|
||||
Version: pkgVersion,
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: pkgName,
|
||||
Version: pkgVersion,
|
||||
PkgHash: &pkgHash,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package haskell
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func TestParseStackYaml(t *testing.T) {
|
||||
expected := []*pkg.Package{
|
||||
{
|
||||
Name: "ShellCheck",
|
||||
Version: "0.8.0",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "ShellCheck",
|
||||
Version: "0.8.0",
|
||||
PkgHash: fixtureP("353c9322847b661e4c6f7c83c2acf8e5c08b682fbe516c7d46c29605937543df"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "colourista",
|
||||
Version: "0.1.0.1",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "colourista",
|
||||
Version: "0.1.0.1",
|
||||
PkgHash: fixtureP("98353ee0e2f5d97d2148513f084c1cd37dfda03e48aa9dd7a017c9d9c0ba710e"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "language-docker",
|
||||
Version: "11.0.0",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "language-docker",
|
||||
Version: "11.0.0",
|
||||
PkgHash: fixtureP("3406ff0c1d592490f53ead8cf2cd22bdf3d79fd125ccaf3add683f6d71c24d55"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "spdx",
|
||||
Version: "1.0.0.2",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "spdx",
|
||||
Version: "1.0.0.2",
|
||||
PkgHash: fixtureP("7dfac9b454ff2da0abb7560f0ffbe00ae442dd5cb76e8be469f77e6988a70fed"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "hspec",
|
||||
Version: "2.9.4",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "hspec",
|
||||
Version: "2.9.4",
|
||||
PkgHash: fixtureP("658a6a74d5a70c040edd6df2a12228c6d9e63082adaad1ed4d0438ad082a0ef3"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "hspec-core",
|
||||
Version: "2.9.4",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "hspec-core",
|
||||
Version: "2.9.4",
|
||||
PkgHash: fixtureP("a126e9087409fef8dcafcd2f8656456527ac7bb163ed4d9cb3a57589042a5fe8"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "hspec-discover",
|
||||
Version: "2.9.4",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "hspec-discover",
|
||||
Version: "2.9.4",
|
||||
PkgHash: fixtureP("fbcf49ecfc3d4da53e797fd0275264cba776ffa324ee223e2a3f4ec2d2c9c4a6"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "stm",
|
||||
Version: "2.5.0.2",
|
||||
Language: pkg.Haskell,
|
||||
Type: pkg.HackagePkg,
|
||||
MetadataType: pkg.HackageMetadataType,
|
||||
Metadata: pkg.HackageMetadata{
|
||||
Name: "stm",
|
||||
Version: "2.5.0.2",
|
||||
PkgHash: fixtureP("e4dc6473faaa75fbd7eccab4e3ee1d651d75bb0e49946ef0b8b751ccde771a55"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fixture, err := os.Open("test-fixtures/stack.yaml")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
}
|
||||
|
||||
// TODO: no relationships are under test yet
|
||||
actual, _, err := parseStackYaml(fixture.Name(), fixture)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
differences := deep.Equal(expected, actual)
|
||||
if differences != nil {
|
||||
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
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
|
||||
@@ -0,0 +1,16 @@
|
||||
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
|
||||
@@ -0,0 +1,75 @@
|
||||
# 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
|
||||
@@ -0,0 +1,66 @@
|
||||
package unionreader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
macho "github.com/anchore/go-macholibre"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
)
|
||||
|
||||
// unionReader is a single interface with all reading functions needed by multi-arch binary catalogers
|
||||
// cataloger.
|
||||
type UnionReader interface {
|
||||
io.Reader
|
||||
io.ReaderAt
|
||||
io.Seeker
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// getReaders extracts one or more io.ReaderAt objects representing binaries that can be processed (multiple binaries in the case for multi-architecture binaries).
|
||||
func GetReaders(f UnionReader) ([]io.ReaderAt, error) {
|
||||
if macho.IsUniversalMachoBinary(f) {
|
||||
machoReaders, err := macho.ExtractReaders(f)
|
||||
if err != nil {
|
||||
log.Debugf("extracting readers: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var readers []io.ReaderAt
|
||||
for _, e := range machoReaders {
|
||||
readers = append(readers, e.Reader)
|
||||
}
|
||||
|
||||
return readers, nil
|
||||
}
|
||||
|
||||
return []io.ReaderAt{f}, nil
|
||||
}
|
||||
|
||||
func GetUnionReader(readerCloser io.ReadCloser) (UnionReader, error) {
|
||||
reader, ok := readerCloser.(UnionReader)
|
||||
if ok {
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(readerCloser)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read contents from binary: %w", err)
|
||||
}
|
||||
|
||||
bytesReader := bytes.NewReader(b)
|
||||
|
||||
reader = struct {
|
||||
io.ReadCloser
|
||||
io.ReaderAt
|
||||
io.Seeker
|
||||
}{
|
||||
ReadCloser: io.NopCloser(bytesReader),
|
||||
ReaderAt: bytesReader,
|
||||
Seeker: bytesReader,
|
||||
}
|
||||
|
||||
return reader, nil
|
||||
}
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
package golang
|
||||
package unionreader
|
||||
|
||||
import (
|
||||
"io"
|
||||
@@ -14,13 +14,13 @@ func Test_getUnionReader_notUnionReader(t *testing.T) {
|
||||
reader := io.NopCloser(strings.NewReader(expectedContents))
|
||||
|
||||
// make certain that the test fixture does not implement the union reader
|
||||
_, ok := reader.(unionReader)
|
||||
_, ok := reader.(UnionReader)
|
||||
require.False(t, ok)
|
||||
|
||||
actual, err := getUnionReader(reader)
|
||||
actual, err := GetUnionReader(reader)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, ok = actual.(unionReader)
|
||||
_, ok = actual.(UnionReader)
|
||||
require.True(t, ok)
|
||||
|
||||
b, err := io.ReadAll(actual)
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
Package portage provides a concrete Cataloger implementation for Gentoo Portage.
|
||||
*/
|
||||
package portage
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
var (
|
||||
cpvRe = regexp.MustCompile(`/([^/]*/[\w+][\w+-]*)-((\d+)((\.\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\d*)*)(-r\d+)?)/CONTENTS$`)
|
||||
)
|
||||
|
||||
type Cataloger struct{}
|
||||
|
||||
// NewPortageCataloger returns a new Portage package cataloger object.
|
||||
func NewPortageCataloger() *Cataloger {
|
||||
return &Cataloger{}
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes a cataloger
|
||||
func (c *Cataloger) Name() string {
|
||||
return "portage-cataloger"
|
||||
}
|
||||
|
||||
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing portage support files.
|
||||
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
dbFileMatches, err := resolver.FilesByGlob(pkg.PortageDBGlob)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to find portage files by glob: %w", err)
|
||||
}
|
||||
var allPackages []pkg.Package
|
||||
for _, dbLocation := range dbFileMatches {
|
||||
cpvMatch := cpvRe.FindStringSubmatch(dbLocation.RealPath)
|
||||
if cpvMatch == nil {
|
||||
return nil, nil, fmt.Errorf("failed to match package and version in %s", dbLocation.RealPath)
|
||||
}
|
||||
entry := pkg.PortageMetadata{
|
||||
// ensure the default value for a collection is never nil since this may be shown as JSON
|
||||
Files: make([]pkg.PortageFileRecord, 0),
|
||||
Package: cpvMatch[1],
|
||||
Version: cpvMatch[2],
|
||||
}
|
||||
|
||||
err = addFiles(resolver, dbLocation, &entry)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
addSize(resolver, dbLocation, &entry)
|
||||
|
||||
p := pkg.Package{
|
||||
Name: entry.Package,
|
||||
Version: entry.Version,
|
||||
Type: pkg.PortagePkg,
|
||||
MetadataType: pkg.PortageMetadataType,
|
||||
Metadata: entry,
|
||||
}
|
||||
addLicenses(resolver, dbLocation, &p)
|
||||
p.FoundBy = c.Name()
|
||||
p.Locations.Add(dbLocation)
|
||||
p.SetID()
|
||||
allPackages = append(allPackages, p)
|
||||
}
|
||||
return allPackages, nil, nil
|
||||
}
|
||||
|
||||
func addFiles(resolver source.FileResolver, dbLocation source.Location, entry *pkg.PortageMetadata) error {
|
||||
contentsReader, err := resolver.FileContentsByLocation(dbLocation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(contentsReader)
|
||||
for scanner.Scan() {
|
||||
line := strings.Trim(scanner.Text(), "\n")
|
||||
fields := strings.Split(line, " ")
|
||||
|
||||
if fields[0] == "obj" {
|
||||
record := pkg.PortageFileRecord{
|
||||
Path: fields[1],
|
||||
}
|
||||
record.Digest = &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: fields[2],
|
||||
}
|
||||
entry.Files = append(entry.Files, record)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addLicenses(resolver source.FileResolver, dbLocation source.Location, p *pkg.Package) {
|
||||
parentPath := filepath.Dir(dbLocation.RealPath)
|
||||
|
||||
location := resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "LICENSE"))
|
||||
|
||||
if location != nil {
|
||||
licenseReader, err := resolver.FileContentsByLocation(*location)
|
||||
if err == nil {
|
||||
findings := internal.NewStringSet()
|
||||
scanner := bufio.NewScanner(licenseReader)
|
||||
scanner.Split(bufio.ScanWords)
|
||||
for scanner.Scan() {
|
||||
token := scanner.Text()
|
||||
if token != "||" && token != "(" && token != ")" {
|
||||
findings.Add(token)
|
||||
}
|
||||
}
|
||||
p.Licenses = findings.ToSlice()
|
||||
|
||||
sort.Strings(p.Licenses)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addSize(resolver source.FileResolver, dbLocation source.Location, entry *pkg.PortageMetadata) {
|
||||
parentPath := filepath.Dir(dbLocation.RealPath)
|
||||
|
||||
location := resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "SIZE"))
|
||||
|
||||
if location != nil {
|
||||
sizeReader, err := resolver.FileContentsByLocation(*location)
|
||||
if err != nil {
|
||||
log.Warnf("failed to fetch portage SIZE (package=%s): %+v", entry.Package, err)
|
||||
} else {
|
||||
scanner := bufio.NewScanner(sizeReader)
|
||||
for scanner.Scan() {
|
||||
line := strings.Trim(scanner.Text(), "\n")
|
||||
size, err := strconv.Atoi(line)
|
||||
if err == nil {
|
||||
entry.InstalledSize = size
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package portage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func TestPortageCataloger(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
expected []pkg.Package
|
||||
}{
|
||||
{
|
||||
name: "go-case",
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "app-containers/skopeo",
|
||||
Version: "1.5.1",
|
||||
FoundBy: "portage-cataloger",
|
||||
Licenses: []string{"Apache-2.0", "BSD", "BSD-2", "CC-BY-SA-4.0", "ISC", "MIT"},
|
||||
Type: pkg.PortagePkg,
|
||||
MetadataType: pkg.PortageMetadataType,
|
||||
Metadata: pkg.PortageMetadata{
|
||||
Package: "app-containers/skopeo",
|
||||
Version: "1.5.1",
|
||||
InstalledSize: 27937835,
|
||||
Files: []pkg.PortageFileRecord{
|
||||
{
|
||||
Path: "/usr/bin/skopeo",
|
||||
Digest: &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: "376c02bd3b22804df8fdfdc895e7dbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/etc/containers/policy.json",
|
||||
Digest: &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: "c01eb6950f03419e09d4fc88cb42ff6f",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/etc/containers/registries.d/default.yaml",
|
||||
Digest: &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: "e6e66cd3c24623e0667f26542e0e08f6",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/var/lib/atomic/sigstore/.keep_app-containers_skopeo-0",
|
||||
Digest: &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: "d41d8cd98f00b204e9800998ecf8427e",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
img := imagetest.GetFixtureImage(t, "docker-archive", "image-portage")
|
||||
|
||||
s, err := source.NewFromImage(img, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := NewPortageCataloger()
|
||||
|
||||
resolver, err := s.FileResolver(source.SquashedScope)
|
||||
if err != nil {
|
||||
t.Errorf("could not get resolver error: %+v", err)
|
||||
}
|
||||
|
||||
actual, _, err := c.Catalog(resolver)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to catalog: %+v", err)
|
||||
}
|
||||
|
||||
if len(actual) != len(test.expected) {
|
||||
for _, a := range actual {
|
||||
t.Logf(" %+v", a)
|
||||
}
|
||||
t.Fatalf("unexpected package count: %d!=%d", len(actual), len(test.expected))
|
||||
}
|
||||
|
||||
// test remaining fields...
|
||||
for _, d := range deep.Equal(actual, test.expected) {
|
||||
t.Errorf("diff: %+v", d)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
FROM scratch
|
||||
COPY . .
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
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
@@ -0,0 +1 @@
|
||||
Apache-2.0 BSD BSD-2 CC-BY-SA-4.0 ISC MIT
|
||||
+1
@@ -0,0 +1 @@
|
||||
27937835
|
||||
@@ -0,0 +1,126 @@
|
||||
package rust
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
rustaudit "github.com/microsoft/go-rustaudit"
|
||||
)
|
||||
|
||||
const catalogerName = "rust-audit-binary-cataloger"
|
||||
|
||||
type Cataloger struct{}
|
||||
|
||||
// NewRustAuditBinaryCataloger returns a new Rust auditable binary cataloger object that can detect dependencies
|
||||
// in binaries produced with https://github.com/Shnatsel/rust-audit
|
||||
func NewRustAuditBinaryCataloger() *Cataloger {
|
||||
return &Cataloger{}
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes a cataloger
|
||||
func (c *Cataloger) Name() string {
|
||||
return catalogerName
|
||||
}
|
||||
|
||||
// Catalog identifies executables then attempts to read Rust dependency information from them
|
||||
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
var pkgs []pkg.Package
|
||||
|
||||
fileMatches, err := resolver.FilesByMIMEType(internal.ExecutableMIMETypeSet.List()...)
|
||||
if err != nil {
|
||||
return pkgs, nil, fmt.Errorf("failed to find bin by mime types: %w", err)
|
||||
}
|
||||
|
||||
for _, location := range fileMatches {
|
||||
readerCloser, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
log.Warnf("rust cataloger: opening file: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
reader, err := unionreader.GetUnionReader(readerCloser)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
versionInfos := scanFile(reader, location.RealPath)
|
||||
internal.CloseAndLogError(readerCloser, location.RealPath)
|
||||
|
||||
for _, versionInfo := range versionInfos {
|
||||
pkgs = append(pkgs, buildRustPkgInfo(location, versionInfo)...)
|
||||
}
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
// scanFile scans file to try to report the Rust crate dependencies
|
||||
func scanFile(reader unionreader.UnionReader, filename string) []rustaudit.VersionInfo {
|
||||
// NOTE: multiple readers are returned to cover universal binaries, which are files
|
||||
// with more than one binary
|
||||
readers, err := unionreader.GetReaders(reader)
|
||||
if err != nil {
|
||||
log.Warnf("rust cataloger: failed to open a binary: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var versionInfos []rustaudit.VersionInfo
|
||||
for _, r := range readers {
|
||||
versionInfo, err := rustaudit.GetDependencyInfo(r)
|
||||
|
||||
if err != nil {
|
||||
if err == rustaudit.ErrNoRustDepInfo {
|
||||
// since the cataloger can only select executables and not distinguish if they are a Rust-compiled
|
||||
// binary, we should not show warnings/logs in this case.
|
||||
return nil
|
||||
}
|
||||
// Use an Info level log here like golang/scan_bin.go
|
||||
log.Infof("rust cataloger: unable to read dependency information (file=%q): %v", filename, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
versionInfos = append(versionInfos, versionInfo)
|
||||
}
|
||||
|
||||
return versionInfos
|
||||
}
|
||||
|
||||
func buildRustPkgInfo(location source.Location, versionInfo rustaudit.VersionInfo) []pkg.Package {
|
||||
var pkgs []pkg.Package
|
||||
|
||||
for _, dep := range versionInfo.Packages {
|
||||
dep := dep
|
||||
p := newRustPackage(&dep, location)
|
||||
if pkg.IsValid(&p) && dep.Kind == rustaudit.Runtime {
|
||||
pkgs = append(pkgs, p)
|
||||
}
|
||||
}
|
||||
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func newRustPackage(dep *rustaudit.Package, location source.Location) pkg.Package {
|
||||
p := pkg.Package{
|
||||
FoundBy: catalogerName,
|
||||
Name: dep.Name,
|
||||
Version: dep.Version,
|
||||
Language: pkg.Rust,
|
||||
Type: pkg.RustPkg,
|
||||
Locations: source.NewLocationSet(location),
|
||||
MetadataType: pkg.RustCargoPackageMetadataType,
|
||||
Metadata: pkg.CargoPackageMetadata{
|
||||
Name: dep.Name,
|
||||
Version: dep.Version,
|
||||
Source: dep.Source,
|
||||
},
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
|
||||
return p
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
Package swift provides a concrete Cataloger implementation for Podfile.lock files.
|
||||
*/
|
||||
package swift
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||
)
|
||||
|
||||
// NewCocoapodsCataloger returns a new Swift Cocoapods lock file cataloger object.
|
||||
func NewCocoapodsCataloger() *common.GenericCataloger {
|
||||
globParsers := map[string]common.ParserFn{
|
||||
"**/Podfile.lock": parsePodfileLock,
|
||||
}
|
||||
|
||||
return common.NewGenericCataloger(nil, globParsers, "cocoapods-cataloger")
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package swift
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ common.ParserFn = parsePodfileLock
|
||||
|
||||
// parsePodfileLock is a parser function for Podfile.lock contents, returning all cocoapods pods discovered.
|
||||
func parsePodfileLock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||
bytes, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to read file: %w", err)
|
||||
}
|
||||
var podfile map[string]interface{}
|
||||
if err = yaml.Unmarshal(bytes, &podfile); err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to parse yaml: %w", err)
|
||||
}
|
||||
|
||||
c, exists := podfile["SPEC CHECKSUMS"]
|
||||
if !exists {
|
||||
return nil, nil, fmt.Errorf("malformed podfile.lock: missing checksums")
|
||||
}
|
||||
checksums := c.(map[string]interface{})
|
||||
p, exists := podfile["PODS"]
|
||||
if !exists {
|
||||
return nil, nil, fmt.Errorf("malformed podfile.lock: missing checksums")
|
||||
}
|
||||
pods := p.([]interface{})
|
||||
|
||||
pkgs := []*pkg.Package{}
|
||||
for _, podInterface := range pods {
|
||||
var podBlob string
|
||||
switch v := podInterface.(type) {
|
||||
case map[string]interface{}:
|
||||
for k := range v {
|
||||
podBlob = k
|
||||
}
|
||||
case string:
|
||||
podBlob = v
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("malformed podfile.lock")
|
||||
}
|
||||
splits := strings.Split(podBlob, " ")
|
||||
podName := splits[0]
|
||||
podVersion := strings.TrimSuffix(strings.TrimPrefix(splits[1], "("), ")")
|
||||
podRootPkg := strings.Split(podName, "/")[0]
|
||||
pkgHash, exists := checksums[podRootPkg]
|
||||
if !exists {
|
||||
return nil, nil, fmt.Errorf("malformed podfile.lock: incomplete checksums")
|
||||
}
|
||||
pkgs = append(pkgs, &pkg.Package{
|
||||
Name: podName,
|
||||
Version: podVersion,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
Language: pkg.Swift,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: podName,
|
||||
Version: podVersion,
|
||||
PkgHash: pkgHash.(string),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
package swift
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func TestParsePodfileLock(t *testing.T) {
|
||||
expected := []*pkg.Package{
|
||||
{
|
||||
Name: "GlossButtonNode",
|
||||
Version: "3.1.2",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "GlossButtonNode",
|
||||
Version: "3.1.2",
|
||||
PkgHash: "4ea1197a744f2fb5fb875fe31caf17ded4762e8f",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINCache",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINCache",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "7a8fc1a691173d21dbddbf86cd515de6efa55086",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINCache/Arc-exception-safe",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINCache/Arc-exception-safe",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "7a8fc1a691173d21dbddbf86cd515de6efa55086",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINCache/Core",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINCache/Core",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "7a8fc1a691173d21dbddbf86cd515de6efa55086",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINOperation",
|
||||
Version: "1.2.1",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINOperation",
|
||||
Version: "1.2.1",
|
||||
PkgHash: "00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINRemoteImage/Core",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINRemoteImage/Core",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "f1295b29f8c5e640e25335a1b2bd9d805171bd01",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINRemoteImage/iOS",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINRemoteImage/iOS",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "f1295b29f8c5e640e25335a1b2bd9d805171bd01",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINRemoteImage/PINCache",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINRemoteImage/PINCache",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "f1295b29f8c5e640e25335a1b2bd9d805171bd01",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Reveal-SDK",
|
||||
Version: "33",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Reveal-SDK",
|
||||
Version: "33",
|
||||
PkgHash: "effba1c940b8337195563c425a6b5862ec875caa",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "SwiftGen",
|
||||
Version: "6.5.1",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "SwiftGen",
|
||||
Version: "6.5.1",
|
||||
PkgHash: "a6d22010845f08fe18fbdf3a07a8e380fd22e0ea",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/AssetsLibrary",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/AssetsLibrary",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/Core",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/Core",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/MapKit",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/MapKit",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/Photos",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/Photos",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/PINRemoteImage",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/PINRemoteImage",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/Video",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/Video",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport/Components",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport/Components",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport/Experiments",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport/Experiments",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport/Extensions",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport/Extensions",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport/LayoutSpecBuilders",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport/LayoutSpecBuilders",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TinyConstraints",
|
||||
Version: "4.0.2",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TinyConstraints",
|
||||
Version: "4.0.2",
|
||||
PkgHash: "7b7ccc0c485bb3bb47082138ff28bc33cd49897f",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fixture, err := os.Open("test-fixtures/Podfile.lock")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
}
|
||||
|
||||
// TODO: no relationships are under test yet
|
||||
actual, _, err := parsePodfileLock(fixture.Name(), fixture)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
differences := deep.Equal(expected, actual)
|
||||
if differences != nil {
|
||||
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
PODS:
|
||||
- GlossButtonNode (3.1.2):
|
||||
- Texture/Core (~> 3)
|
||||
- TextureSwiftSupport (>= 3.10.0)
|
||||
- PINCache (3.0.3):
|
||||
- PINCache/Arc-exception-safe (= 3.0.3)
|
||||
- PINCache/Core (= 3.0.3)
|
||||
- PINCache/Arc-exception-safe (3.0.3):
|
||||
- PINCache/Core
|
||||
- PINCache/Core (3.0.3):
|
||||
- PINOperation (~> 1.2.1)
|
||||
- PINOperation (1.2.1)
|
||||
- PINRemoteImage/Core (3.0.3):
|
||||
- PINOperation
|
||||
- PINRemoteImage/iOS (3.0.3):
|
||||
- PINRemoteImage/Core
|
||||
- PINRemoteImage/PINCache (3.0.3):
|
||||
- PINCache (~> 3.0.3)
|
||||
- PINRemoteImage/Core
|
||||
- Reveal-SDK (33)
|
||||
- SwiftGen (6.5.1)
|
||||
- Texture (3.1.0):
|
||||
- Texture/AssetsLibrary (= 3.1.0)
|
||||
- Texture/Core (= 3.1.0)
|
||||
- Texture/MapKit (= 3.1.0)
|
||||
- Texture/Photos (= 3.1.0)
|
||||
- Texture/PINRemoteImage (= 3.1.0)
|
||||
- Texture/Video (= 3.1.0)
|
||||
- Texture/AssetsLibrary (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/Core (3.1.0)
|
||||
- Texture/MapKit (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/Photos (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/PINRemoteImage (3.1.0):
|
||||
- PINRemoteImage/iOS (~> 3.0.0)
|
||||
- PINRemoteImage/PINCache
|
||||
- Texture/Core
|
||||
- Texture/Video (3.1.0):
|
||||
- Texture/Core
|
||||
- TextureSwiftSupport (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/Components (= 3.13.0)
|
||||
- TextureSwiftSupport/Experiments (= 3.13.0)
|
||||
- TextureSwiftSupport/Extensions (= 3.13.0)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders (= 3.13.0)
|
||||
- TextureSwiftSupport/Components (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders
|
||||
- TextureSwiftSupport/Experiments (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/Extensions (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TinyConstraints (4.0.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- GlossButtonNode
|
||||
- Reveal-SDK
|
||||
- SwiftGen
|
||||
- Texture
|
||||
- TextureSwiftSupport
|
||||
- TinyConstraints
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- GlossButtonNode
|
||||
- PINCache
|
||||
- PINOperation
|
||||
- PINRemoteImage
|
||||
- Reveal-SDK
|
||||
- SwiftGen
|
||||
- Texture
|
||||
- TextureSwiftSupport
|
||||
- TinyConstraints
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
GlossButtonNode: 4ea1197a744f2fb5fb875fe31caf17ded4762e8f
|
||||
PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086
|
||||
PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20
|
||||
PINRemoteImage: f1295b29f8c5e640e25335a1b2bd9d805171bd01
|
||||
Reveal-SDK: effba1c940b8337195563c425a6b5862ec875caa
|
||||
SwiftGen: a6d22010845f08fe18fbdf3a07a8e380fd22e0ea
|
||||
Texture: 2e8ab2519452515f7f5a520f5a8f7e0a413abfa3
|
||||
TextureSwiftSupport: c515c7927fab92d0d9485f49b885b8c5de34fbfb
|
||||
TinyConstraints: 7b7ccc0c485bb3bb47082138ff28bc33cd49897f
|
||||
|
||||
PODFILE CHECKSUM: 07aa55f54421f6e6d3a920c11716a89fc9243d1b
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
@@ -0,0 +1,27 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
)
|
||||
|
||||
var _ urlIdentifier = (*CocoapodsMetadata)(nil)
|
||||
|
||||
type CocoapodsMetadata struct {
|
||||
Name string `mapstructure:"name" json:"name"`
|
||||
Version string `mapstructure:"version" json:"version"`
|
||||
PkgHash string `mapstructure:"pkgHash" json:"pkgHash"`
|
||||
}
|
||||
|
||||
func (m CocoapodsMetadata) PackageURL(_ *linux.Release) string {
|
||||
var qualifiers packageurl.Qualifiers
|
||||
|
||||
return packageurl.NewPackageURL(
|
||||
packageurl.TypeCocoapods,
|
||||
"",
|
||||
m.Name,
|
||||
m.Version,
|
||||
qualifiers,
|
||||
"",
|
||||
).ToString()
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
)
|
||||
|
||||
var _ urlIdentifier = (*HackageMetadata)(nil)
|
||||
|
||||
type HackageMetadata struct {
|
||||
Name string `mapstructure:"name" json:"name"`
|
||||
Version string `mapstructure:"version" json:"version"`
|
||||
PkgHash *string `mapstructure:"pkgHash" json:"pkgHash,omitempty"`
|
||||
SnapshotURL *string `mapstructure:"snapshotURL" json:"snapshotURL,omitempty"`
|
||||
}
|
||||
|
||||
func (m HackageMetadata) PackageURL(_ *linux.Release) string {
|
||||
var qualifiers packageurl.Qualifiers
|
||||
|
||||
return packageurl.NewPackageURL(
|
||||
packageurl.TypeHackage,
|
||||
"",
|
||||
m.Name,
|
||||
m.Version,
|
||||
qualifiers,
|
||||
"",
|
||||
).ToString()
|
||||
}
|
||||
@@ -21,7 +21,9 @@ const (
|
||||
Rust Language = "rust"
|
||||
Dart Language = "dart"
|
||||
Dotnet Language = "dotnet"
|
||||
Swift Language = "swift"
|
||||
CPP Language = "c++"
|
||||
Haskell Language = "haskell"
|
||||
)
|
||||
|
||||
// AllLanguages is a set of all programming languages detected by syft.
|
||||
@@ -35,7 +37,9 @@ var AllLanguages = []Language{
|
||||
Rust,
|
||||
Dart,
|
||||
Dotnet,
|
||||
Swift,
|
||||
CPP,
|
||||
Haskell,
|
||||
}
|
||||
|
||||
// String returns the string representation of the language.
|
||||
@@ -72,8 +76,12 @@ func LanguageByName(name string) Language {
|
||||
return Dart
|
||||
case packageurl.TypeDotnet:
|
||||
return Dotnet
|
||||
case packageurl.TypeCocoapods, packageurl.TypeSwift, string(CocoapodsPkg):
|
||||
return Swift
|
||||
case packageurl.TypeConan, string(CPP):
|
||||
return CPP
|
||||
case packageurl.TypeHackage, string(Haskell):
|
||||
return Haskell
|
||||
default:
|
||||
return UnknownLanguage
|
||||
}
|
||||
|
||||
@@ -50,10 +50,18 @@ func TestLanguageFromPURL(t *testing.T) {
|
||||
purl: "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist",
|
||||
want: Java,
|
||||
},
|
||||
{
|
||||
purl: "pkg:cocoapods/GlossButtonNode@3.1.2",
|
||||
want: Swift,
|
||||
},
|
||||
{
|
||||
purl: "pkg:conan/catch2@2.13.8",
|
||||
want: CPP,
|
||||
},
|
||||
{
|
||||
purl: "pkg:hackage/HTTP@4000.3.16",
|
||||
want: Haskell,
|
||||
},
|
||||
}
|
||||
|
||||
var languages []string
|
||||
@@ -183,6 +191,18 @@ func TestLanguageByName(t *testing.T) {
|
||||
name: "dotnet",
|
||||
language: Dotnet,
|
||||
},
|
||||
{
|
||||
name: "swift",
|
||||
language: Swift,
|
||||
},
|
||||
{
|
||||
name: "pod",
|
||||
language: Swift,
|
||||
},
|
||||
{
|
||||
name: "cocoapods",
|
||||
language: Swift,
|
||||
},
|
||||
{
|
||||
name: "unknown",
|
||||
language: UnknownLanguage,
|
||||
@@ -195,6 +215,14 @@ func TestLanguageByName(t *testing.T) {
|
||||
name: "c++",
|
||||
language: CPP,
|
||||
},
|
||||
{
|
||||
name: "hackage",
|
||||
language: Haskell,
|
||||
},
|
||||
{
|
||||
name: "haskell",
|
||||
language: Haskell,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -25,7 +25,10 @@ const (
|
||||
KbPackageMetadataType MetadataType = "KbPackageMetadata"
|
||||
GolangBinMetadataType MetadataType = "GolangBinMetadata"
|
||||
PhpComposerJSONMetadataType MetadataType = "PhpComposerJsonMetadata"
|
||||
CocoapodsMetadataType MetadataType = "CocoapodsMetadataType"
|
||||
ConanaMetadataType MetadataType = "ConanaMetadataType"
|
||||
PortageMetadataType MetadataType = "PortageMetadata"
|
||||
HackageMetadataType MetadataType = "HackageMetadataType"
|
||||
)
|
||||
|
||||
var AllMetadataTypes = []MetadataType{
|
||||
@@ -43,7 +46,10 @@ var AllMetadataTypes = []MetadataType{
|
||||
KbPackageMetadataType,
|
||||
GolangBinMetadataType,
|
||||
PhpComposerJSONMetadataType,
|
||||
CocoapodsMetadataType,
|
||||
ConanaMetadataType,
|
||||
PortageMetadataType,
|
||||
HackageMetadataType,
|
||||
}
|
||||
|
||||
var MetadataTypeByName = map[MetadataType]reflect.Type{
|
||||
@@ -61,5 +67,8 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{
|
||||
KbPackageMetadataType: reflect.TypeOf(KbPackageMetadata{}),
|
||||
GolangBinMetadataType: reflect.TypeOf(GolangBinMetadata{}),
|
||||
PhpComposerJSONMetadataType: reflect.TypeOf(PhpComposerJSONMetadata{}),
|
||||
CocoapodsMetadataType: reflect.TypeOf(CocoapodsMetadata{}),
|
||||
ConanaMetadataType: reflect.TypeOf(ConanMetadata{}),
|
||||
PortageMetadataType: reflect.TypeOf(PortageMetadata{}),
|
||||
HackageMetadataType: reflect.TypeOf(HackageMetadata{}),
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
|
||||
const PortageDBGlob = "**/var/db/pkg/*/*/CONTENTS"
|
||||
|
||||
// PortageMetadata represents all captured data for a Package package DB entry.
|
||||
type PortageMetadata struct {
|
||||
Package string `mapstructure:"Package" json:"package"`
|
||||
Version string `mapstructure:"Version" json:"version"`
|
||||
InstalledSize int `mapstructure:"InstalledSize" json:"installedSize" cyclonedx:"installedSize"`
|
||||
Files []PortageFileRecord `json:"files"`
|
||||
}
|
||||
|
||||
// PortageFileRecord represents a single file attributed to a portage package.
|
||||
type PortageFileRecord struct {
|
||||
Path string `json:"path"`
|
||||
Digest *file.Digest `json:"digest,omitempty"`
|
||||
}
|
||||
@@ -23,7 +23,10 @@ const (
|
||||
KbPkg Type = "msrc-kb"
|
||||
DartPubPkg Type = "dart-pub"
|
||||
DotnetPkg Type = "dotnet"
|
||||
CocoapodsPkg Type = "pod"
|
||||
ConanPkg Type = "conan"
|
||||
PortagePkg Type = "portage"
|
||||
HackagePkg Type = "hackage"
|
||||
)
|
||||
|
||||
// AllPkgs represents all supported package types
|
||||
@@ -43,7 +46,10 @@ var AllPkgs = []Type{
|
||||
KbPkg,
|
||||
DartPubPkg,
|
||||
DotnetPkg,
|
||||
CocoapodsPkg,
|
||||
ConanPkg,
|
||||
PortagePkg,
|
||||
HackagePkg,
|
||||
}
|
||||
|
||||
// PackageURLType returns the PURL package type for the current package.
|
||||
@@ -75,8 +81,14 @@ func (t Type) PackageURLType() string {
|
||||
return packageurl.TypePub
|
||||
case DotnetPkg:
|
||||
return packageurl.TypeDotnet
|
||||
case CocoapodsPkg:
|
||||
return packageurl.TypeCocoapods
|
||||
case ConanPkg:
|
||||
return packageurl.TypeConan
|
||||
case PortagePkg:
|
||||
return "portage"
|
||||
case HackagePkg:
|
||||
return packageurl.TypeHackage
|
||||
default:
|
||||
// TODO: should this be a "generic" purl type instead?
|
||||
return ""
|
||||
@@ -120,8 +132,14 @@ func TypeByName(name string) Type {
|
||||
return DartPubPkg
|
||||
case packageurl.TypeDotnet:
|
||||
return DotnetPkg
|
||||
case packageurl.TypeCocoapods:
|
||||
return CocoapodsPkg
|
||||
case packageurl.TypeConan:
|
||||
return ConanPkg
|
||||
case packageurl.TypeHackage:
|
||||
return HackagePkg
|
||||
case "portage":
|
||||
return PortagePkg
|
||||
default:
|
||||
return UnknownPkg
|
||||
}
|
||||
|
||||
@@ -68,10 +68,18 @@ func TestTypeFromPURL(t *testing.T) {
|
||||
purl: "pkg:alpm/arch/linux@5.10.0?arch=x86_64&distro=arch",
|
||||
expected: AlpmPkg,
|
||||
},
|
||||
{
|
||||
purl: "pkg:cocoapods/GlossButtonNode@3.1.2",
|
||||
expected: CocoapodsPkg,
|
||||
},
|
||||
{
|
||||
purl: "pkg:conan/catch2@2.13.8",
|
||||
expected: ConanPkg,
|
||||
},
|
||||
{
|
||||
purl: "pkg:hackage/HTTP@4000.3.16",
|
||||
expected: HackagePkg,
|
||||
},
|
||||
}
|
||||
|
||||
var pkgTypes []string
|
||||
@@ -83,6 +91,7 @@ func TestTypeFromPURL(t *testing.T) {
|
||||
// testing microsoft packages and jenkins-plugins is not valid for purl at this time
|
||||
expectedTypes.Remove(string(KbPkg))
|
||||
expectedTypes.Remove(string(JenkinsPluginPkg))
|
||||
expectedTypes.Remove(string(PortagePkg))
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(string(test.expected), func(t *testing.T) {
|
||||
|
||||
+5
-5
@@ -41,14 +41,14 @@ func URL(p Package, release *linux.Release) string {
|
||||
|
||||
switch {
|
||||
case purlType == "":
|
||||
// there is no purl type, don't attempt to craft a purl
|
||||
// TODO: should this be a "generic" purl type instead?
|
||||
return ""
|
||||
purlType = packageurl.TypeGeneric
|
||||
case p.Type == GoModulePkg:
|
||||
re := regexp.MustCompile(`(/)[^/]*$`)
|
||||
fields := re.Split(p.Name, -1)
|
||||
namespace = fields[0]
|
||||
name = strings.TrimPrefix(p.Name, namespace+"/")
|
||||
if len(fields) > 1 {
|
||||
namespace = fields[0]
|
||||
name = strings.TrimPrefix(p.Name, namespace+"/")
|
||||
}
|
||||
case p.Type == NpmPkg:
|
||||
fields := strings.SplitN(p.Name, "/", 2)
|
||||
if len(fields) > 1 {
|
||||
|
||||
+50
-1
@@ -25,6 +25,15 @@ func TestPackageURL(t *testing.T) {
|
||||
},
|
||||
expected: "pkg:golang/github.com/anchore/syft@v0.1.0",
|
||||
},
|
||||
{
|
||||
name: "golang short name",
|
||||
pkg: Package{
|
||||
Name: "go.opencensus.io",
|
||||
Version: "v0.23.0",
|
||||
Type: GoModulePkg,
|
||||
},
|
||||
expected: "pkg:golang/go.opencensus.io@v0.23.0",
|
||||
},
|
||||
{
|
||||
name: "pub",
|
||||
pkg: Package{
|
||||
@@ -208,6 +217,20 @@ func TestPackageURL(t *testing.T) {
|
||||
|
||||
expected: "pkg:alpm/arch/linux@5.10.0?distro=arch-rolling",
|
||||
},
|
||||
{
|
||||
name: "cocoapods",
|
||||
pkg: Package{
|
||||
Name: "GlossButtonNode",
|
||||
Version: "3.1.2",
|
||||
Language: Swift,
|
||||
Type: CocoapodsPkg,
|
||||
Metadata: CocoapodsMetadata{
|
||||
Name: "GlossButtonNode",
|
||||
Version: "3.1.2",
|
||||
},
|
||||
},
|
||||
expected: "pkg:cocoapods/GlossButtonNode@3.1.2",
|
||||
},
|
||||
{
|
||||
name: "conan",
|
||||
pkg: Package{
|
||||
@@ -223,6 +246,21 @@ func TestPackageURL(t *testing.T) {
|
||||
},
|
||||
expected: "pkg:conan/catch2@2.13.8",
|
||||
},
|
||||
{
|
||||
name: "hackage",
|
||||
pkg: Package{
|
||||
Name: "HTTP",
|
||||
Version: "4000.3.16",
|
||||
Type: HackagePkg,
|
||||
Language: Haskell,
|
||||
MetadataType: HackageMetadataType,
|
||||
Metadata: HackageMetadata{
|
||||
Name: "HTTP",
|
||||
Version: "4000.3.16",
|
||||
},
|
||||
},
|
||||
expected: "pkg:hackage/HTTP@4000.3.16",
|
||||
},
|
||||
}
|
||||
|
||||
var pkgTypes []string
|
||||
@@ -233,10 +271,11 @@ func TestPackageURL(t *testing.T) {
|
||||
|
||||
// testing microsoft packages is not valid for purl at this time
|
||||
expectedTypes.Remove(string(KbPkg))
|
||||
expectedTypes.Remove(string(PortagePkg))
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if test.pkg.Type != "" {
|
||||
if test.pkg.Type != "" && !contains(pkgTypes, string(test.pkg.Type)) {
|
||||
pkgTypes = append(pkgTypes, string(test.pkg.Type))
|
||||
}
|
||||
actual := URL(test.pkg, test.distro)
|
||||
@@ -249,3 +288,13 @@ func TestPackageURL(t *testing.T) {
|
||||
}
|
||||
assert.ElementsMatch(t, expectedTypes.List(), pkgTypes, "missing one or more package types to test against (maybe a package type was added?)")
|
||||
}
|
||||
|
||||
func contains(values []string, val string) bool {
|
||||
for _, v := range values {
|
||||
if val == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestPackagesCmdFlags(t *testing.T) {
|
||||
name: "squashed-scope-flag",
|
||||
args: []string{"packages", "-o", "json", "-s", "squashed", coverageImage},
|
||||
assertions: []traitAssertion{
|
||||
assertPackageCount(33),
|
||||
assertPackageCount(34),
|
||||
assertSuccessfulReturnCode,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -222,10 +222,16 @@ func getSyftBinaryLocation(t testing.TB) string {
|
||||
}
|
||||
|
||||
func getSyftBinaryLocationByOS(t testing.TB, goOS string) string {
|
||||
// note: for amd64 we need to update the snapshot location with the v1 suffix
|
||||
// see : https://goreleaser.com/customization/build/#why-is-there-a-_v1-suffix-on-amd64-builds
|
||||
archPath := runtime.GOARCH
|
||||
if runtime.GOARCH == "amd64" {
|
||||
archPath = fmt.Sprintf("%s_v1", archPath)
|
||||
}
|
||||
// note: there is a subtle - vs _ difference between these versions
|
||||
switch goOS {
|
||||
case "darwin", "linux":
|
||||
return path.Join(repoRoot(t), fmt.Sprintf("snapshot/%s-build_%s_%s/syft", goOS, goOS, runtime.GOARCH))
|
||||
return path.Join(repoRoot(t), fmt.Sprintf("snapshot/%s-build_%s_%s/syft", goOS, goOS, archPath))
|
||||
default:
|
||||
t.Fatalf("unsupported OS: %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ else
|
||||
fi
|
||||
|
||||
# run syft
|
||||
SYFT_PATH="${DISTDIR}/darwin-build_darwin_amd64/syft"
|
||||
SYFT_PATH="${DISTDIR}/darwin-build_darwin_amd64_v1/syft"
|
||||
chmod 755 "${SYFT_PATH}"
|
||||
"${SYFT_PATH}" version
|
||||
SYFT_CHECK_FOR_APP_UPDATE=0 "${SYFT_PATH}" packages docker-archive:${TEST_IMAGE_TAR} -vv -o json > "${REPORT}"
|
||||
|
||||
+1
-1
@@ -53,4 +53,4 @@ ${ACC_DIR}/compare.py \
|
||||
${GOLDEN_REPORT} \
|
||||
${REPORT} | tee ${RESULTSDIR}/acceptance-${TEST_TYPE}.txt
|
||||
|
||||
EXIT_CODE=0
|
||||
EXIT_CODE=0
|
||||
|
||||
@@ -71,6 +71,13 @@ run_test_case test_positive_snapshot_download_asset "linux" "amd64" "deb"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "arm64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "arm64" "rpm"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "arm64" "deb"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "ppc64le" "tar.gz"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "ppc64le" "rpm"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "ppc64le" "deb"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "s390x" "tar.gz"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "s390x" "rpm"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "s390x" "deb"
|
||||
|
||||
run_test_case test_positive_snapshot_download_asset "darwin" "amd64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_download_asset "darwin" "arm64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_download_asset "windows" "amd64" "zip"
|
||||
|
||||
@@ -26,6 +26,12 @@ test_positive_snapshot_install_asset() {
|
||||
expected_path="${install_dir}/${binary}"
|
||||
assertFileExists "${expected_path}" "install_asset os=${os} arch=${arch} format=${format}"
|
||||
|
||||
# directory structure for arch has been updated as of go 1.18
|
||||
# https://goreleaser.com/customization/build/#why-is-there-a-_v1-suffix-on-amd64-buildsjk
|
||||
if [ $arch == "amd64" ]; then
|
||||
arch="amd64_v1"
|
||||
fi
|
||||
|
||||
assertFilesEqual \
|
||||
"$(snapshot_dir)/${os}-build_${os}_${arch}/${binary}" \
|
||||
"${expected_path}" \
|
||||
@@ -76,6 +82,8 @@ trap 'teardown_snapshot_server ${worker_pid}' EXIT
|
||||
# exercise all possible archive assets (not rpm/deb/dmg) against a snapshot build
|
||||
run_test_case test_positive_snapshot_install_asset "linux" "amd64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "linux" "arm64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "linux" "ppc64le" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "linux" "s390x" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "darwin" "amd64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "darwin" "arm64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "windows" "amd64" "zip"
|
||||
|
||||
@@ -251,6 +251,70 @@ var dirOnlyTestCases = []testCase{
|
||||
"junit": "4.12",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find cocoapods packages",
|
||||
pkgType: pkg.CocoapodsPkg,
|
||||
pkgLanguage: pkg.Swift,
|
||||
pkgInfo: map[string]string{
|
||||
"GlossButtonNode": "3.1.2",
|
||||
"PINCache": "3.0.3",
|
||||
"PINCache/Arc-exception-safe": "3.0.3",
|
||||
"PINCache/Core": "3.0.3",
|
||||
"PINOperation": "1.2.1",
|
||||
"PINRemoteImage/Core": "3.0.3",
|
||||
"PINRemoteImage/iOS": "3.0.3",
|
||||
"PINRemoteImage/PINCache": "3.0.3",
|
||||
"Reveal-SDK": "33",
|
||||
"SwiftGen": "6.5.1",
|
||||
"Texture": "3.1.0",
|
||||
"Texture/AssetsLibrary": "3.1.0",
|
||||
"Texture/Core": "3.1.0",
|
||||
"Texture/MapKit": "3.1.0",
|
||||
"Texture/Photos": "3.1.0",
|
||||
"Texture/PINRemoteImage": "3.1.0",
|
||||
"Texture/Video": "3.1.0",
|
||||
"TextureSwiftSupport": "3.13.0",
|
||||
"TextureSwiftSupport/Components": "3.13.0",
|
||||
"TextureSwiftSupport/Experiments": "3.13.0",
|
||||
"TextureSwiftSupport/Extensions": "3.13.0",
|
||||
"TextureSwiftSupport/LayoutSpecBuilders": "3.13.0",
|
||||
"TinyConstraints": "4.0.2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find hackage packages",
|
||||
pkgType: pkg.HackagePkg,
|
||||
pkgLanguage: pkg.Haskell,
|
||||
pkgInfo: map[string]string{
|
||||
"Cabal": "3.2.1.0",
|
||||
"Diff": "0.4.1",
|
||||
"HTTP": "4000.3.16",
|
||||
"HUnit": "1.6.2.0",
|
||||
"OneTuple": "0.3.1",
|
||||
"Only": "0.1",
|
||||
"PyF": "0.10.2.0",
|
||||
"QuickCheck": "2.14.2",
|
||||
"RSA": "2.4.1",
|
||||
"SHA": "1.6.4.4",
|
||||
"Spock": "0.14.0.0",
|
||||
"ShellCheck": "0.8.0",
|
||||
"colourista": "0.1.0.1",
|
||||
"language-docker": "11.0.0",
|
||||
"spdx": "1.0.0.2",
|
||||
"hspec": "2.9.4",
|
||||
"hspec-core": "2.9.4",
|
||||
"hspec-discover": "2.9.4",
|
||||
"stm": "2.5.0.2",
|
||||
"configurator-pg": "0.2.6",
|
||||
"hasql-dynamic-statements": "0.3.1.1",
|
||||
"hasql-implicits": "0.1.0.4",
|
||||
"hasql-pool": "0.5.2.2",
|
||||
"lens-aeson": "1.1.3",
|
||||
"optparse-applicative": "0.16.1.0",
|
||||
"protolude": "0.3.2",
|
||||
"ptr": "0.16.8.2",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var commonTestCases = []testCase{
|
||||
@@ -277,6 +341,14 @@ var commonTestCases = []testCase{
|
||||
"netbase": "5.4",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find portage packages",
|
||||
pkgType: pkg.PortagePkg,
|
||||
pkgInfo: map[string]string{
|
||||
"app-containers/skopeo": "1.5.1",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "find jenkins plugins",
|
||||
pkgType: pkg.JenkinsPluginPkg,
|
||||
|
||||
@@ -54,7 +54,7 @@ func BenchmarkImagePackageCatalogers(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestPkgCoverageImage(t *testing.T) {
|
||||
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope)
|
||||
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope, false)
|
||||
|
||||
observedLanguages := internal.NewStringSet()
|
||||
definedLanguages := internal.NewStringSet()
|
||||
@@ -67,7 +67,9 @@ func TestPkgCoverageImage(t *testing.T) {
|
||||
definedLanguages.Remove(pkg.Rust.String())
|
||||
definedLanguages.Remove(pkg.Dart.String())
|
||||
definedLanguages.Remove(pkg.Dotnet.String())
|
||||
definedLanguages.Remove(string(pkg.Swift.String()))
|
||||
definedLanguages.Remove(pkg.CPP.String())
|
||||
definedLanguages.Remove(pkg.Haskell.String())
|
||||
|
||||
observedPkgs := internal.NewStringSet()
|
||||
definedPkgs := internal.NewStringSet()
|
||||
@@ -81,7 +83,9 @@ func TestPkgCoverageImage(t *testing.T) {
|
||||
definedPkgs.Remove(string(pkg.RustPkg))
|
||||
definedPkgs.Remove(string(pkg.DartPubPkg))
|
||||
definedPkgs.Remove(string(pkg.DotnetPkg))
|
||||
definedPkgs.Remove(string(pkg.CocoapodsPkg))
|
||||
definedPkgs.Remove(string(pkg.ConanPkg))
|
||||
definedPkgs.Remove(string(pkg.HackagePkg))
|
||||
|
||||
var cases []testCase
|
||||
cases = append(cases, commonTestCases...)
|
||||
|
||||
@@ -36,7 +36,7 @@ var convertibleFormats = []sbom.Format{
|
||||
func TestConvertCmd(t *testing.T) {
|
||||
for _, format := range convertibleFormats {
|
||||
t.Run(format.ID().String(), func(t *testing.T) {
|
||||
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope)
|
||||
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope, false)
|
||||
format := syft.FormatByID(syftjson.ID)
|
||||
|
||||
f, err := ioutil.TempFile("", "test-convert-sbom-")
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestDistroImage(t *testing.T) {
|
||||
sbom, _ := catalogFixtureImage(t, "image-distro-id", source.SquashedScope)
|
||||
sbom, _ := catalogFixtureImage(t, "image-distro-id", source.SquashedScope, false)
|
||||
|
||||
expected := &linux.Release{
|
||||
PrettyName: "BusyBox v1.31.1",
|
||||
|
||||
@@ -64,7 +64,7 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("%s", test.formatOption), func(t *testing.T) {
|
||||
for _, image := range images {
|
||||
originalSBOM, _ := catalogFixtureImage(t, image, source.SquashedScope)
|
||||
originalSBOM, _ := catalogFixtureImage(t, image, source.SquashedScope, false)
|
||||
|
||||
format := syft.FormatByID(test.formatOption)
|
||||
require.NotNil(t, format)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestMarinerDistroless(t *testing.T) {
|
||||
sbom, _ := catalogFixtureImage(t, "image-mariner-distroless", source.SquashedScope)
|
||||
sbom, _ := catalogFixtureImage(t, "image-mariner-distroless", source.SquashedScope, false)
|
||||
|
||||
expectedPkgs := 12
|
||||
actualPkgs := 0
|
||||
|
||||
@@ -56,7 +56,7 @@ func TestPackageDeduplication(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(string(tt.scope), func(t *testing.T) {
|
||||
sbom, _ := catalogFixtureImage(t, "image-vertical-package-dups", tt.scope)
|
||||
sbom, _ := catalogFixtureImage(t, "image-vertical-package-dups", tt.scope, false)
|
||||
|
||||
assert.Equal(t, tt.packageCount, sbom.Artifacts.PackageCatalog.PackageCount())
|
||||
for name, expectedInstanceCount := range tt.instanceCount {
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestPackageOwnershipRelationships(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.fixture, func(t *testing.T) {
|
||||
sbom, _ := catalogFixtureImage(t, test.fixture, source.SquashedScope)
|
||||
sbom, _ := catalogFixtureImage(t, test.fixture, source.SquashedScope, false)
|
||||
|
||||
output := bytes.NewBufferString("")
|
||||
err := syftjson.Format().Encode(output, sbom)
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
func TestRegression212ApkBufferSize(t *testing.T) {
|
||||
// This is a regression test for issue #212 (https://github.com/anchore/syft/issues/212) in which the apk db could
|
||||
// not be processed due to a scanner buffer that was too small
|
||||
sbom, _ := catalogFixtureImage(t, "image-large-apk-data", source.SquashedScope)
|
||||
sbom, _ := catalogFixtureImage(t, "image-large-apk-data", source.SquashedScope, false)
|
||||
|
||||
expectedPkgs := 58
|
||||
actualPkgs := 0
|
||||
|
||||
@@ -16,7 +16,7 @@ func TestRegressionGoArchDiscovery(t *testing.T) {
|
||||
)
|
||||
// This is a regression test to make sure the way we detect go binary packages
|
||||
// stays consistent and reproducible as the tool chain evolves
|
||||
sbom, _ := catalogFixtureImage(t, "image-go-bin-arch-coverage", source.SquashedScope)
|
||||
sbom, _ := catalogFixtureImage(t, "image-go-bin-arch-coverage", source.SquashedScope, false)
|
||||
|
||||
var actualELF, actualWIN, actualMACOS int
|
||||
|
||||
|
||||
@@ -6,5 +6,5 @@ import (
|
||||
)
|
||||
|
||||
func TestRegressionJavaNoMainPackage(t *testing.T) { // Regression: https://github.com/anchore/syft/issues/252
|
||||
catalogFixtureImage(t, "image-java-no-main-package", source.SquashedScope)
|
||||
catalogFixtureImage(t, "image-java-no-main-package", source.SquashedScope, false)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func TestRustAudit(t *testing.T) {
|
||||
sbom, _ := catalogFixtureImage(t, "image-rust-auditable", source.SquashedScope, true)
|
||||
|
||||
expectedPkgs := 2
|
||||
actualPkgs := 0
|
||||
for range sbom.Artifacts.PackageCatalog.Enumerate(pkg.RustPkg) {
|
||||
actualPkgs += 1
|
||||
}
|
||||
|
||||
if actualPkgs != expectedPkgs {
|
||||
t.Errorf("unexpected number of Rust packages: %d != %d", expectedPkgs, actualPkgs)
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func TestSqliteRpm(t *testing.T) {
|
||||
// This is a regression test for issue #469 (https://github.com/anchore/syft/issues/469). Recent RPM
|
||||
// based distribution store package data in an sqlite database
|
||||
sbom, _ := catalogFixtureImage(t, "image-sqlite-rpmdb", source.SquashedScope)
|
||||
sbom, _ := catalogFixtureImage(t, "image-sqlite-rpmdb", source.SquashedScope, false)
|
||||
|
||||
expectedPkgs := 139
|
||||
actualPkgs := 0
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
PODS:
|
||||
- GlossButtonNode (3.1.2):
|
||||
- Texture/Core (~> 3)
|
||||
- TextureSwiftSupport (>= 3.10.0)
|
||||
- PINCache (3.0.3):
|
||||
- PINCache/Arc-exception-safe (= 3.0.3)
|
||||
- PINCache/Core (= 3.0.3)
|
||||
- PINCache/Arc-exception-safe (3.0.3):
|
||||
- PINCache/Core
|
||||
- PINCache/Core (3.0.3):
|
||||
- PINOperation (~> 1.2.1)
|
||||
- PINOperation (1.2.1)
|
||||
- PINRemoteImage/Core (3.0.3):
|
||||
- PINOperation
|
||||
- PINRemoteImage/iOS (3.0.3):
|
||||
- PINRemoteImage/Core
|
||||
- PINRemoteImage/PINCache (3.0.3):
|
||||
- PINCache (~> 3.0.3)
|
||||
- PINRemoteImage/Core
|
||||
- Reveal-SDK (33)
|
||||
- SwiftGen (6.5.1)
|
||||
- Texture (3.1.0):
|
||||
- Texture/AssetsLibrary (= 3.1.0)
|
||||
- Texture/Core (= 3.1.0)
|
||||
- Texture/MapKit (= 3.1.0)
|
||||
- Texture/Photos (= 3.1.0)
|
||||
- Texture/PINRemoteImage (= 3.1.0)
|
||||
- Texture/Video (= 3.1.0)
|
||||
- Texture/AssetsLibrary (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/Core (3.1.0)
|
||||
- Texture/MapKit (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/Photos (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/PINRemoteImage (3.1.0):
|
||||
- PINRemoteImage/iOS (~> 3.0.0)
|
||||
- PINRemoteImage/PINCache
|
||||
- Texture/Core
|
||||
- Texture/Video (3.1.0):
|
||||
- Texture/Core
|
||||
- TextureSwiftSupport (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/Components (= 3.13.0)
|
||||
- TextureSwiftSupport/Experiments (= 3.13.0)
|
||||
- TextureSwiftSupport/Extensions (= 3.13.0)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders (= 3.13.0)
|
||||
- TextureSwiftSupport/Components (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders
|
||||
- TextureSwiftSupport/Experiments (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/Extensions (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TinyConstraints (4.0.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- GlossButtonNode
|
||||
- Reveal-SDK
|
||||
- SwiftGen
|
||||
- Texture
|
||||
- TextureSwiftSupport
|
||||
- TinyConstraints
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- GlossButtonNode
|
||||
- PINCache
|
||||
- PINOperation
|
||||
- PINRemoteImage
|
||||
- Reveal-SDK
|
||||
- SwiftGen
|
||||
- Texture
|
||||
- TextureSwiftSupport
|
||||
- TinyConstraints
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
GlossButtonNode: 4ea1197a744f2fb5fb875fe31caf17ded4762e8f
|
||||
PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086
|
||||
PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20
|
||||
PINRemoteImage: f1295b29f8c5e640e25335a1b2bd9d805171bd01
|
||||
Reveal-SDK: effba1c940b8337195563c425a6b5862ec875caa
|
||||
SwiftGen: a6d22010845f08fe18fbdf3a07a8e380fd22e0ea
|
||||
Texture: 2e8ab2519452515f7f5a520f5a8f7e0a413abfa3
|
||||
TextureSwiftSupport: c515c7927fab92d0d9485f49b885b8c5de34fbfb
|
||||
TinyConstraints: 7b7ccc0c485bb3bb47082138ff28bc33cd49897f
|
||||
|
||||
PODFILE CHECKSUM: 07aa55f54421f6e6d3a920c11716a89fc9243d1b
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
@@ -0,0 +1,16 @@
|
||||
active-repositories: hackage.haskell.org:merge
|
||||
constraints: any.Cabal ==3.2.1.0,
|
||||
any.Diff ==0.4.1,
|
||||
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
|
||||
@@ -0,0 +1,16 @@
|
||||
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
|
||||
@@ -0,0 +1,75 @@
|
||||
# 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
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
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
@@ -0,0 +1 @@
|
||||
Apache-2.0 BSD BSD-2 CC-BY-SA-4.0 ISC MIT
|
||||
+1
@@ -0,0 +1 @@
|
||||
27937835
|
||||
@@ -0,0 +1,2 @@
|
||||
# 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
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func catalogFixtureImage(t *testing.T, fixtureImageName string, scope source.Scope) (sbom.SBOM, *source.Source) {
|
||||
func catalogFixtureImage(t *testing.T, fixtureImageName string, scope source.Scope, allCatalogers bool) (sbom.SBOM, *source.Source) {
|
||||
imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
||||
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
|
||||
userInput := "docker-archive:" + tarPath
|
||||
@@ -25,6 +25,9 @@ func catalogFixtureImage(t *testing.T, fixtureImageName string, scope source.Sco
|
||||
|
||||
// TODO: this would be better with functional options (after/during API refactor)
|
||||
c := cataloger.DefaultConfig()
|
||||
if allCatalogers {
|
||||
c.Catalogers = []string{"all"}
|
||||
}
|
||||
c.Search.Scope = scope
|
||||
pkgCatalog, relationships, actualDistro, err := syft.CatalogPackages(theSource, c)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user