Compare commits

...
26 Commits
Author SHA1 Message Date
Christopher Angelo Phillips a7966a4d9d update stereoscope to latest (#1181) 2022-08-29 19:28:19 +00:00
anchore-actions-token-generator[bot]andspiffcs 4ebf6aff86 Update syft bootstrap tools to latest versions. (#1180)
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2022-08-29 10:30:58 -04:00
Christopher Angelo PhillipsandAlex Goodman 615f933d98 Bug fix for 1095 - syft conversion option error (#1177)
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2022-08-25 17:36:15 -04:00
anchore-actions-token-generator[bot]andspiffcs 2c882f6239 Update syft bootstrap tools to latest versions. (#1176)
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2022-08-25 09:14:24 -04:00
Keith Zantow 7d4f333ec4 enhance development support on macOS ARM (#1163) 2022-08-24 13:48:14 -04:00
Scott Andrews 5e93d1ea1e Capture if a node module is private (#1161) 2022-08-24 17:07:56 +00:00
Keith Zantow 57c5413fe0 Find version numbers from jars with different naming conventions (#1174) 2022-08-24 12:56:53 -04:00
anchore-actions-token-generator[bot]andWeston Steimel b0fc955e0c Update syft bootstrap tools to latest versions. (#1171)
* Update syft bootstrap tools to latest versions.

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
Co-authored-by: Weston Steimel <weston.steimel@anchore.com>
2022-08-23 20:36:59 +01:00
Weston Steimel 6949a2500f Fix update-bootstrap-tools workflow (#1170) 2022-08-22 16:17:28 +00:00
Weston Steimel 5282820b5d workflow to create automated PRs to update bootstrap tools (#1167) 2022-08-22 11:28:24 -04:00
cpendery c56d3b5eef feat: add support for licenses in package-lock json v2 (#1164) 2022-08-22 11:23:44 -04:00
Marco Deicas 13296880cd External sources configuration (#1158) 2022-08-22 11:22:18 -04:00
cpendery e9221ae25d feat: add support for pnpm (#1166) 2022-08-22 10:45:55 -04:00
Justin Chadwell f3c3d3d98e Prevent symlinks causing duplicate package-file relationships (#1168) 2022-08-22 10:29:00 -04:00
Keith Zantow 21eb772060 Associate node package licenses from node_modules (#1152) 2022-08-16 14:14:02 -04:00
Josh Bressers d1390b315e Give the contributing guide a substantial rework (#1155) 2022-08-16 10:43:25 -04:00
Justin Chadwell 3db6911865 fix: extract file ids correctly for spdx-json (#1156)
Previously, extracting relationships between packages and files was not
completing correctly, as SPDXRef- ElementIDs were being compared to raw
IDs, and so never matched. This patch ensures that we always compare
ElementIDs, to ensure that the hasFiles field is correctly populated.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2022-08-11 14:06:36 -04:00
Alex Goodman 2693a8c19a metadata decoding should be optional (#1154)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-08-10 16:20:53 +00:00
anchore-actions-token-generator[bot]andkzantow 1344889766 Update Stereoscope to 84004345484edb881f1cc1d841115da8abda06c3 (#1151)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: kzantow <kzantow@users.noreply.github.com>
2022-08-09 08:59:35 +00:00
04387301ce Add modularitylabel metadata to RPM type records generated by syft (#1148)
* bump cosign to v1.10.1 (#1144)

Signed-off-by: Daniel Nurmi <nurmi@anchore.com>

* Add modularitylabel metadata to RPM type records generated by syft. Fixes #1145.

Signed-off-by: Daniel Nurmi <nurmi@anchore.com>

* update to address lint failures

Signed-off-by: Daniel Nurmi <nurmi@anchore.com>

* Update syft/pkg/rpmdb_metadata.go

Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Daniel Nurmi <nurmi@anchore.com>

* update json schema to match camel case

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Weston Steimel <weston.steimel@anchore.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2022-08-08 11:52:32 +00:00
anchore-actions-token-generator[bot]andkzantow 4df84d380d Update Stereoscope to 1c79d5c84abcc54466417fcc17c844a4875888a1 (#1149)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: kzantow <kzantow@users.noreply.github.com>
2022-08-06 10:52:42 -04:00
Christopher Angelo Phillips 5be7e081f5 retraction for mispublished versions (#1147)
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2022-08-06 10:52:21 -04:00
Tom Fay 621f0fe082 cataloger configuration is respected regardless of source (#1142) 2022-08-04 21:14:23 +00:00
Neil Levine 644ca00e20 Update README.md (#1146) 2022-08-04 21:13:28 +00:00
Weston Steimel fce83321ba bump cosign to v1.10.1 (#1144) 2022-08-04 19:03:57 +00:00
Keith Zantow 69bde44c6e Update stereoscope to get rid of the replace directive (#1140) 2022-08-03 12:24:20 -04:00
102 changed files with 3510 additions and 621 deletions
+3
View File
@@ -11,6 +11,9 @@ ignore-packages:
# packageurl-go is released under the MIT license located in the root of the repo at /mit.LICENSE
- github.com/anchore/packageurl-go
# crypto/internal/boring is released under the openSSL license as a part of the Golang Standard Libary
- crypto/internal/boring
# from: https://github.com/spdx/tools-golang/blob/main/LICENSE.code
# The tools-golang source code is provided and may be used, at your option,
# under either:
+1 -1
View File
@@ -148,7 +148,7 @@ jobs:
with:
status: ${{ job.status }}
fields: repo,workflow,action,eventName
text: "A new Syft release is ready to be manually published: https://github.com/anchore/syft/releases"
text: "A new Syft release has been published: https://github.com/anchore/syft/releases/tag/${{ github.ref_name }}"
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
if: ${{ success() }}
@@ -0,0 +1,75 @@
name: PR for latest versions of bootstrap tools
on:
schedule:
- cron: "0 8 * * *" # 3 AM EST
workflow_dispatch:
env:
GO_VERSION: "1.18.x"
GO_STABLE_VERSION: true
jobs:
update-bootstrap-tools:
runs-on: ubuntu-latest
if: github.repository == 'anchore/syft' # only run for main repo
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
- run: |
GOLANGCILINT_LATEST_VERSION=$(go list -m -json github.com/golangci/golangci-lint@latest 2>/dev/null | jq -r '.Version')
BOUNCER_LATEST_VERSION=$(go list -m -json github.com/wagoodman/go-bouncer@latest 2>/dev/null | jq -r '.Version')
CHRONICLE_LATEST_VERSION=$(go list -m -json github.com/anchore/chronicle@latest 2>/dev/null | jq -r '.Version')
GORELEASER_LATEST_VERSION=$(go list -m -json github.com/goreleaser/goreleaser@latest 2>/dev/null | jq -r '.Version')
YAJSV_LATEST_VERSION=$(go list -m -json github.com/neilpa/yajsv@latest 2>/dev/null | jq -r '.Version')
COSIGN_LATEST_VERSION=$(go list -m -json github.com/sigstore/cosign@latest 2>/dev/null | jq -r '.Version')
# update version variables in the Makefile
sed -r -i -e 's/^(GOLANGCILINT_VERSION = ).*/\1'${GOLANGCILINT_LATEST_VERSION}'/' Makefile
sed -r -i -e 's/^(BOUNCER_VERSION = ).*/\1'${BOUNCER_LATEST_VERSION}'/' Makefile
sed -r -i -e 's/^(CHRONICLE_VERSION = ).*/\1'${CHRONICLE_LATEST_VERSION}'/' Makefile
sed -r -i -e 's/^(GORELEASER_VERSION = ).*/\1'${GORELEASER_LATEST_VERSION}'/' Makefile
sed -r -i -e 's/^(YAJSV_VERSION = ).*/\1'${YAJSV_LATEST_VERSION}'/' Makefile
sed -r -i -e 's/^(COSIGN_VERSION = ).*/\1'${COSIGN_LATEST_VERSION}'/' Makefile
# update cosign in go.mod as well
go get github.com/sigstore/cosign@$COSIGN_LATEST_VERSION
go mod tidy
# export the versions for use with create-pull-request
echo "::set-output name=GOLANGCILINT::$GOLANGCILINT_LATEST_VERSION"
echo "::set-output name=BOUNCER::$BOUNCER_LATEST_VERSION"
echo "::set-output name=CHRONICLE::$CHRONICLE_LATEST_VERSION"
echo "::set-output name=GORELEASER::$GORELEASER_LATEST_VERSION"
echo "::set-output name=YAJSV::$YAJSV_LATEST_VERSION"
echo "::set-output name=COSIGN::$COSIGN_LATEST_VERSION"
id: latest-versions
- uses: tibdex/github-app-token@v1
id: generate-token
with:
app_id: ${{ secrets.TOKEN_APP_ID }}
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
- uses: peter-evans/create-pull-request@v4
with:
signoff: true
delete-branch: true
branch: auto/latest-bootstrap-tools
labels: dependencies
commit-message: 'Update syft bootstrap tools to latest versions.'
title: 'Update syft bootstrap tools to latest versions.'
body: |
- [golangci-lint ${{ steps.latest-versions.outputs.GOLANGCILINT }}](https://github.com/golangci/golangci-lint/releases/tag/${{ steps.latest-versions.outputs.GOLANGCILINT }})
- [bouncer ${{ steps.latest-versions.outputs.BOUNCER }}](https://github.com/wagoodman/go-bouncer/releases/tag/${{ steps.latest-versions.outputs.BOUNCER }})
- [chronicle ${{ steps.latest-versions.outputs.CHRONICLE }}](https://github.com/anchore/chronicle/releases/tag/${{ steps.latest-versions.outputs.CHRONICLE }})
- [goreleaser ${{ steps.latest-versions.outputs.GORELEASER }}](https://github.com/goreleaser/goreleaser/releases/tag/${{ steps.latest-versions.outputs.GORELEASER }})
- [yajsv ${{ steps.latest-versions.outputs.YAJSV }}](https://github.com/neilpa/yajsv/releases/tag/${{ steps.latest-versions.outputs.YAJSV }})
- [cosign ${{ steps.latest-versions.outputs.COSIGN }}](https://github.com/sigstore/cosign/releases/tag/${{ steps.latest-versions.outputs.COSIGN }})
This is an auto-generated pull request to update all of the bootstrap tools to the latest versions.
token: ${{ steps.generate-token.outputs.token }}
+73 -21
View File
@@ -2,6 +2,57 @@
If you are looking to contribute to this project and want to open a GitHub pull request ("PR"), there are a few guidelines of what we are looking for in patches. Make sure you go through this document and ensure that your code proposal is aligned.
## Setting up your environment
Before you can contribute to Syft, you need to configure your development environment.
### Debian setup
You will need to install Go. The version on https://go.dev works best, using the system golang doesn't always work the way you might expect.
At the time of writing, Go 1.19 does not work correctly with Syft. Please use Go 1.18 for now.
You will also need Docker. There's no reason the system packages shouldn't work, but we used the official Docker package. You can find instructions for installing Docker in Debian [here](https://docs.docker.com/engine/install/debian/).
You also need to install some Debian packages
```sh
sudo apt-get install build-essential zip bc libxml2-utils git
```
## Configuring Git
You will need to configure your git client with your name and email address. This is easily done from the command line.
```text
$ git config --global user.name "John Doe"
$ git config --global user.email "john.doe@example.com"
```
This username and email address will matter later in this guide.
## Fork the repo
You should fork the Syft repo using the "Fork" button at the top right of the Syft GitHub [site](https://github.com/anchore/syft/). You will be doing your development in your fork, then submit a pull request to Syft. There are many resources how to use GitHub effectively, we will not cover those here.
## Adding a feature or fix
If you look at the Syft [Issue](https://github.com/anchore/syft/issues) there are plenty of bugs and feature requests. Maybe look at the [good first issue](https://github.com/anchore/syft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) list if you're not sure where to start.
## Commit guidelines
In the Syft project we like commits and pull requests (PR) to be easy to understand and review. Open source thrives best when everything happening is over documented and small enough to be understood.
### Granular commits
Please try to make every commit as simple as possible, but no simpler. The idea is that each commit should be a logical unit of code. Try not to commit too many tiny changes, for example every line changed in a file as a separate commit. And also try not to make a commit enormous, for example committing all your work at the end of the day.
Rather than try to follow a strict guide on what is or is not best, we try to be flexible and simple in this space. Do what makes the most sense for the changes you are trying to include.
### Commit title and description
Remember that the message you leave for a commit is for the reviewer in the present, and for someone (maybe you) changing something in the future. Please make sure the title and description used is easy to understand and explains what was done. Jokes and clever comments generally don't age well in commit messages. Just the facts please.
## Sign off your work
The `sign-off` is an added line at the end of the explanation for the commit, certifying that you wrote it or otherwise have the right to submit it as an open-source patch. By submitting a contribution, you agree to be bound by the terms of the DCO Version 1.1 and Apache License Version 2.0.
@@ -44,13 +95,6 @@ When committing your change, you can add the required line manually so that it l
Signed-off-by: John Doe <john.doe@example.com>
```
Alternatively, configure your Git client with your name and email to use the `-s` flag when creating a commit:
```text
$ git config --global user.name "John Doe"
$ git config --global user.email "john.doe@example.com"
```
Creating a signed-off commit is then possible with `-s` or `--signoff`:
```text
@@ -70,21 +114,9 @@ Date: Mon Aug 1 11:27:13 2020 -0400
Signed-off-by: John Doe <john.doe@example.com>
```
[//]: # (TODO: Commit guidelines, granular commits)
[//]: # (TODO: Commit guidelines, descriptive messages)
[//]: # (TODO: Commit guidelines, commit title, extra body description)
[//]: # (TODO: PR title and description)
## Test your changes
This project has a `Makefile` which includes many helpers running both unit and integration tests. Although PRs will have automatic checks for these, it is useful to run them locally, ensuring they pass before submitting changes. Ensure you've bootstrapped once before running tests:
This project has a `Makefile` which includes many helpers running both unit and integration tests. You can run `make help` to see all the options. Although PRs will have automatic checks for these, it is useful to run them locally, ensuring they pass before submitting changes. Ensure you've bootstrapped once before running tests:
```text
$ make bootstrap
@@ -97,6 +129,26 @@ $ make unit
$ make integration
```
You can also run `make all` to run a more extensive test suite, but there is additional configuration that will be needed for those tests to run correctly. We will not cover the extra steps here.
## Pull Request
If you made it this far and all the tests are passing, it's time to submit a Pull Request (PR) for Syft. Submitting a PR is always a scary moment as what happens next can be an unknown. The Syft project strives to be easy to work with, we appreciate all contributions. Nobody is going to yell at you or try to make you feel bad. We love contributions and know how scary that first PR can be.
### PR Title and Description
Just like the commit title and description mentioned above, the PR title and description is very important for letting others know what's happening. Please include any details you think a reviewer will need to more properly review your PR.
A PR that is very large or poorly described has a higher likelihood of being pushed to the end of the list. Reviewers like PRs they can understand and quickly review.
### What to expect next
Please be patient with the project. We try to review PRs in a timely manner, but this is highly dependent on all the other tasks we have going on. It's OK to ask for a status update every week or two, it's not OK to ask for a status update every day.
It's very likely the reviewer will have questions and suggestions for changes to your PR. If your changes don't match the current style and flow of the other code, expect a request to change what you've done.
## Document your changes
When proposed changes are modifying user-facing functionality or output, it is expected the PR will include updates to the documentation as well.
And lastly, when proposed changes are modifying user-facing functionality or output, it is expected the PR will include updates to the documentation as well. Syft is not a project that is heavy on documentation. This will mostly be updating the README and help for the tool.
If nobody knows new features exist, they can't use them!
+14 -8
View File
@@ -9,6 +9,12 @@ SNAPSHOT_CMD=$(RELEASE_CMD) --skip-publish --snapshot
VERSION=$(shell git describe --dirty --always --tags)
COMPARE_TEST_IMAGE = centos:8.2.2004
COMPARE_DIR = ./test/compare
GOLANGCILINT_VERSION = v1.49.0
BOUNCER_VERSION = v0.4.0
CHRONICLE_VERSION = v0.4.1
GORELEASER_VERSION = v1.11.0
YAJSV_VERSION = v1.4.0
COSIGN_VERSION = v1.11.1
# formatting variables
BOLD := $(shell tput -T linux bold)
@@ -32,7 +38,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_v1/$(BIN))
SNAPSHOT_BIN=$(realpath $(shell pwd)/$(SNAPSHOTDIR)/$(OS)-build_$(OS)_amd64_v1/$(BIN))
## Variable assertions
@@ -105,13 +111,13 @@ $(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.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.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.10.0
GO111MODULE=off GOBIN=$(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)/ $(GOLANGCILINT_VERSION)
curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ $(BOUNCER_VERSION)
curl -sSfL https://raw.githubusercontent.com/anchore/chronicle/main/install.sh | sh -s -- -b $(TEMPDIR)/ $(CHRONICLE_VERSION)
.github/scripts/goreleaser-install.sh -d -b $(TEMPDIR)/ $(GORELEASER_VERSION)
GOBIN="$(realpath $(TEMPDIR))" go install github.com/neilpa/yajsv@$(YAJSV_VERSION)
GOBIN="$(realpath $(TEMPDIR))" go install github.com/sigstore/cosign/cmd/cosign@$(COSIGN_VERSION)
.PHONY: bootstrap-go
bootstrap-go:
+111 -65
View File
@@ -17,6 +17,8 @@ A CLI tool and Go library for generating a Software Bill of Materials (SBOM) fro
- Agenda: https://docs.google.com/document/d/1ZtSAa6fj2a6KRWviTn3WoJm09edvrNUp4Iz_dOjjyY8/edit?usp=sharing (join [this group](https://groups.google.com/g/anchore-oss-community) for write access)
- All are welcome!
For commercial support options with Syft or Grype, please [contact Anchore](https://get.anchore.com/contact/)
![syft-demo](https://user-images.githubusercontent.com/590471/90277200-2a253000-de33-11ea-893f-32c219eea11a.gif)
## Features
@@ -93,7 +95,7 @@ nix-shell -p syft
## Getting started
#### SBOM
### SBOM
To generate an SBOM for a container image:
@@ -107,67 +109,9 @@ The above output includes only software that is visible in the container (i.e.,
syft <image> --scope all-layers
```
#### Format conversion (experimental)
The ability to convert existing SBOMs means you can create SBOMs in different formats quickly, without the need to regenerate the SBOM from scratch, which may take significantly more time.
```
syft convert <ORIGINAL-SBOM-FILE> -o <NEW-SBOM-FORMAT>[=<NEW-SBOM-FILE>]
```
This feature is experimental and data might be lost when converting formats. Packages are the main SBOM component easily transferable across formats, whereas files and relationships, as well as other information Syft doesn't support, are more likely to be lost.
We support formats with wide community usage AND good encode/decode support by Syft. The supported formats are:
- Syft JSON
- SPDX 2.2 JSON
- SPDX 2.2 tag-value
- CycloneDX 1.4 JSON
- CycloneDX 1.4 XML
Conversion example:
```sh
syft alpine:latest -o syft-json=sbom.syft.json # generate a syft SBOM
syft convert sbom.syft.json -o cyclonedx-json=sbom.cdx.json # convert it to CycloneDX
```
#### SBOM attestation
### Keyless support
Syft supports generating attestations using cosign's [keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) signatures.
To use this feature with a format like CycloneDX json simply run:
```
syft attest --output cyclonedx-json <IMAGE WITH OCI WRITE ACCESS>
```
This command will open a web browser and allow the user to authenticate their OIDC identity as the root of trust for the attestation (Github, Google, Microsoft).
After authenticating, Syft will upload the attestation to the OCI registry specified by the image that the user has write access to.
You will need to make sure your credentials are configured for the OCI registry you are uploading to so that the attestation can write successfully.
Users can then verify the attestation(or any image with attestations) by running:
```
COSIGN_EXPERIMENTAL=1 cosign verify-attestation <IMAGE_WITH_ATTESTATIONS>
```
Users should see that the uploaded attestation claims are validated, the claims exist within the transparency log, and certificates on the attestations were verified against [fulcio](https://github.com/SigStore/fulcio).
There will also be a printout of the certificates subject `<user identity>` and the certificate issuer URL: `<provider of user identity (Github, Google, Microsoft)>`:
```
Certificate subject: test.email@testdomain.com
Certificate issuer URL: https://accounts.google.com
```
### Local private key support
To generate an SBOM attestation for a container image using a local private key:
```
syft attest --output [FORMAT] --key [KEY] [SOURCE] [flags]
```
The above output is in the form of the [DSSE envelope](https://github.com/secure-systems-lab/dsse/blob/master/envelope.md#dsse-envelope).
The payload is a base64 encoded `in-toto` statement with the generated SBOM as the predicate. For details on workflows using this command see [here](#adding-an-sbom-to-an-image-as-an-attestation-using-syft).
### Supported sources
## Supported sources
Syft can generate a SBOM from a variety of sources:
@@ -193,6 +137,47 @@ file:path/to/yourproject/file read directly from a path on disk (any
registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
```
#### Default Cataloger Configuration by scan type
##### Image Scanning:
- alpmdb
- rpmdb
- dpkgdb
- apkdb
- portage
- ruby-gemspec
- python-package
- php-composer-installed Cataloger
- javascript-package
- java
- go-module-binary
- dotnet-deps
##### Directory Scanning:
- alpmdb
- apkdb
- dpkgdb
- portage
- rpmdb
- ruby-gemfile
- python-index
- python-package
- php-composer-lock
- javascript-lock
- java
- java-pom
- go-module-binary
- go-mod-file
- rust-cargo-lock
- dartlang-lock
- dotnet-deps
- cocoapods
- conan
- hackage
#### Non Default:
- cargo-auditable-binary
### Excluding file paths
Syft can exclude files and paths from being scanned within a source by using glob expressions
@@ -230,13 +215,13 @@ Where the `formats` available are:
- `table`: A columnar summary (default).
- `template`: Lets the user specify the output format. See ["Using templates"](#using-templates) below.
#### Using templates
## Using templates
Syft lets you define custom output formats, using [Go templates](https://pkg.go.dev/text/template). Here's how it works:
- Define your format as a Go template, and save this template as a file.
- Set the output format to "template" (`-o template`).
- Set the output format to "template" (`-o template`).
- Specify the path to the template file (`-t ./path/to/custom.template`).
@@ -263,7 +248,7 @@ Which would produce output like:
Syft also includes a vast array of utility templating functions from [sprig](http://masterminds.github.io/sprig/) apart from the default Golang [text/template](https://pkg.go.dev/text/template#hdr-Functions) to allow users to customize the output format.
#### Multiple outputs
## Multiple outputs
Syft can also output _multiple_ files in differing formats by appending
`=<file>` to the option, for example to output Syft JSON and SPDX JSON:
@@ -313,7 +298,7 @@ Here's a simple workflow to mount this config file as a secret into a container
config.json: <base64 encoded config.json>
```
`kubectl apply -f secret.yaml`
`kubectl apply -f secret.yaml`
2. Create your pod running syft. The env `DOCKER_CONFIG` is important because it advertises where to look for the credential file. In the below example, setting `DOCKER_CONFIG=/config` informs syft that credentials can be found at `/config/config.json`. This is why we used `config.json` as the key for our secret. When mounted into containers the secrets' key is used as the filename. The `volumeMounts` section mounts our secret to `/config`. The `volumes` section names our volume and leverages the secret we created in step one.
@@ -344,13 +329,74 @@ Here's a simple workflow to mount this config file as a secret into a container
secretName: registry-config
```
`kubectl apply -f pod.yaml`
`kubectl apply -f pod.yaml`
3. The user can now run `kubectl logs syft-private-registry-demo`. The logs should show the Syft analysis for the `<private_image>` provided in the pod configuration.
Using the above information, users should be able to configure private registry access without having to do so in the `grype` or `syft` configuration files. They will also not be dependent on a Docker daemon, (or some other runtime software) for registry configuration and access.
## Format conversion (experimental)
The ability to convert existing SBOMs means you can create SBOMs in different formats quickly, without the need to regenerate the SBOM from scratch, which may take significantly more time.
```
syft convert <ORIGINAL-SBOM-FILE> -o <NEW-SBOM-FORMAT>[=<NEW-SBOM-FILE>]
```
This feature is experimental and data might be lost when converting formats. Packages are the main SBOM component easily transferable across formats, whereas files and relationships, as well as other information Syft doesn't support, are more likely to be lost.
We support formats with wide community usage AND good encode/decode support by Syft. The supported formats are:
- Syft JSON
- SPDX 2.2 JSON
- SPDX 2.2 tag-value
- CycloneDX 1.4 JSON
- CycloneDX 1.4 XML
Conversion example:
```sh
syft alpine:latest -o syft-json=sbom.syft.json # generate a syft SBOM
syft convert sbom.syft.json -o cyclonedx-json=sbom.cdx.json # convert it to CycloneDX
```
## Attestation (experimental)
### Keyless support
Syft supports generating attestations using cosign's [keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) signatures.
To use this feature with a format like CycloneDX json simply run:
```
syft attest --output cyclonedx-json <IMAGE WITH OCI WRITE ACCESS>
```
This command will open a web browser and allow the user to authenticate their OIDC identity as the root of trust for the attestation (Github, Google, Microsoft).
After authenticating, Syft will upload the attestation to the OCI registry specified by the image that the user has write access to.
You will need to make sure your credentials are configured for the OCI registry you are uploading to so that the attestation can write successfully.
Users can then verify the attestation(or any image with attestations) by running:
```
COSIGN_EXPERIMENTAL=1 cosign verify-attestation <IMAGE_WITH_ATTESTATIONS>
```
Users should see that the uploaded attestation claims are validated, the claims exist within the transparency log, and certificates on the attestations were verified against [fulcio](https://github.com/SigStore/fulcio).
There will also be a printout of the certificates subject `<user identity>` and the certificate issuer URL: `<provider of user identity (Github, Google, Microsoft)>`:
```
Certificate subject: test.email@testdomain.com
Certificate issuer URL: https://accounts.google.com
```
#### Local private key support
To generate an SBOM attestation for a container image using a local private key:
```
syft attest --output [FORMAT] --key [KEY] [SOURCE] [flags]
```
The above output is in the form of the [DSSE envelope](https://github.com/secure-systems-lab/dsse/blob/master/envelope.md#dsse-envelope).
The payload is a base64 encoded `in-toto` statement with the generated SBOM as the predicate. For details on workflows using this command see [here](#adding-an-sbom-to-an-image-as-an-attestation-using-syft).
## Configuration
Configuration search paths:
+3 -2
View File
@@ -31,7 +31,8 @@ const indent = " "
// at this level. Values from the config should only be used after `app.LoadAllValues` has been called.
// Cobra does not have knowledge of the user provided flags until the `RunE` block of each command.
// `RunE` is the earliest that the complete application configuration can be loaded.
// nolint:funlen
//
//nolint:funlen
func New() (*cobra.Command, error) {
app := &config.Application{}
@@ -48,7 +49,7 @@ func New() (*cobra.Command, error) {
// root options are also passed to the attestCmd so that a user provided config location can be discovered
attestCmd := Attest(v, app, ro)
poweruserCmd := PowerUser(v, app, ro)
convertCmd := Convert(v, app, ro)
convertCmd := Convert(v, app, ro, po)
// rootCmd is currently an alias for the packages command
rootCmd := &cobra.Command{
+9 -1
View File
@@ -2,6 +2,7 @@ package cli
import (
"fmt"
"log"
"github.com/anchore/syft/cmd/syft/cli/convert"
"github.com/anchore/syft/cmd/syft/cli/options"
@@ -17,7 +18,8 @@ const (
`
)
func Convert(v *viper.Viper, app *config.Application, ro *options.RootOptions) *cobra.Command {
//nolint:dupl
func Convert(v *viper.Viper, app *config.Application, ro *options.RootOptions, po *options.PackagesOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "convert [SOURCE-SBOM] -o [FORMAT]",
Short: "Convert between SBOM formats",
@@ -43,5 +45,11 @@ func Convert(v *viper.Viper, app *config.Application, ro *options.RootOptions) *
return convert.Run(cmd.Context(), app, args)
},
}
err := po.AddFlags(cmd, v)
if err != nil {
log.Fatal(err)
}
return cmd
}
+2 -1
View File
@@ -14,7 +14,8 @@ import (
// eventLoop listens to worker errors (from execution path), worker events (from a partybus subscription), and
// signal interrupts. Is responsible for handling each event relative to a given UI an to coordinate eventing until
// an eventual graceful exit.
// nolint:funlen
//
//nolint:funlen
func EventLoop(workerErrs <-chan error, signals <-chan os.Signal, subscription *partybus.Subscription, cleanupFn func(), uxs ...ui.UI) error {
defer cleanupFn()
events := subscription.Events()
+9
View File
@@ -26,6 +26,7 @@ type PackagesOptions struct {
OverwriteExistingImage bool
ImportTimeout uint
Catalogers []string
ExternalSourcesEnabled bool
}
var _ Interface = (*PackagesOptions)(nil)
@@ -70,9 +71,13 @@ func (o *PackagesOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
cmd.Flags().UintVarP(&o.ImportTimeout, "import-timeout", "", 30,
"set a timeout duration (in seconds) for the upload to Anchore Enterprise")
cmd.Flags().BoolVarP(&o.ExternalSourcesEnabled, "external-sources-enabled", "", false,
"shut off any use of external sources during sbom generation (default false")
return bindPackageConfigOptions(cmd.Flags(), v)
}
//nolint:funlen
func bindPackageConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
// Formatting & Input options //////////////////////////////////////////////
@@ -104,6 +109,10 @@ func bindPackageConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
return err
}
if err := v.BindPFlag("external_sources.external-sources-enabled", flags.Lookup("external-sources-enabled")); err != nil {
return err
}
// Upload options //////////////////////////////////////////////////////////
if err := v.BindPFlag("anchore.host", flags.Lookup("host")); err != nil {
+2
View File
@@ -5,6 +5,7 @@ import (
"log"
"github.com/anchore/syft/cmd/syft/cli/options"
"github.com/anchore/syft/cmd/syft/cli/packages"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/config"
@@ -44,6 +45,7 @@ const (
packagesHelp = packagesExample + packagesSchemeHelp
)
//nolint:dupl
func Packages(v *viper.Viper, app *config.Application, ro *options.RootOptions, po *options.PackagesOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "packages [SOURCE]",
+61 -64
View File
@@ -13,7 +13,6 @@ require (
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-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
@@ -35,7 +34,7 @@ require (
// pinned to pull in 386 arch fix: https://github.com/scylladb/go-set/commit/cc7b2070d91ebf40d233207b633e28f5bd8f03a5
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e
github.com/sergi/go-diff v1.2.0
github.com/sirupsen/logrus v1.8.1
github.com/sirupsen/logrus v1.9.0
github.com/spdx/tools-golang v0.2.0
github.com/spf13/afero v1.8.2
github.com/spf13/cobra v1.5.0
@@ -48,21 +47,22 @@ require (
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb
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-20220624214902-1bab6f366d9e
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/Masterminds/sprig/v3 v3.2.2
github.com/anchore/stereoscope v0.0.0-20220829182958-659c89aa659f
github.com/docker/docker v20.10.17+incompatible
github.com/google/go-containerregistry v0.10.0
github.com/google/go-containerregistry v0.11.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/sigstore/cosign v1.11.1
github.com/sigstore/rekor v0.11.0
github.com/sigstore/sigstore v1.4.0
github.com/vbatts/go-mtree v0.5.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -70,36 +70,33 @@ require (
require (
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/azure-sdk-for-go v66.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
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect
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/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.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 v1.16.11 // indirect
github.com/aws/aws-sdk-go-v2/config v1.17.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.12.14 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19 // 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.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/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.17 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 // indirect
github.com/aws/smithy-go v1.12.1 // 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
@@ -113,7 +110,7 @@ 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.11.4 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.12.0 // 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
@@ -132,28 +129,27 @@ require (
github.com/fsnotify/fsnotify v1.5.4 // 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.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/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.20.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/loads v0.21.1 // indirect
github.com/go-openapi/loads v0.21.2 // indirect
github.com/go-openapi/runtime v0.24.1 // indirect
github.com/go-openapi/spec v0.20.6 // indirect
github.com/go-openapi/spec v0.20.7 // indirect
github.com/go-openapi/strfmt v0.21.3 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-openapi/validate v0.22.0 // indirect
github.com/go-piv/piv-go v1.9.0 // indirect
github.com/go-piv/piv-go v1.10.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.11.0 // indirect
github.com/go-restruct/restruct v1.2.0-alpha // 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-jwt/jwt/v4 v4.4.2 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
@@ -171,27 +167,26 @@ require (
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/grpc-ecosystem/grpc-gateway/v2 v2.11.2 // 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
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
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-20211028175153-1c139d1cc84b // indirect
github.com/jhump/protoreflect v1.10.3 // indirect
github.com/jhump/protoreflect v1.12.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // 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.15.4 // indirect
github.com/klauspost/compress v1.15.9 // 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
github.com/letsencrypt/boulder v0.0.0-20220723181115-27de4befb95e // indirect
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@@ -210,12 +205,12 @@ 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.6 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.34.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // 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
@@ -224,7 +219,7 @@ require (
github.com/segmentio/ksuid v1.0.4 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/sigstore/fulcio v0.1.2-0.20220114150912-86a2036f9bc7 // indirect
github.com/sigstore/fulcio v0.5.3 // indirect
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
github.com/soheilhy/cmux v0.1.5 // indirect
github.com/spf13/cast v1.5.0 // indirect
@@ -232,7 +227,8 @@ require (
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/sylabs/sif/v2 v2.7.2 // indirect
github.com/sylabs/squashfs v0.6.1 // 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
@@ -244,7 +240,7 @@ require (
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/urfave/cli v1.22.7 // indirect
github.com/vbatts/tar-split v0.11.2 // indirect
github.com/xanzy/go-gitlab v0.69.0 // indirect
github.com/xanzy/go-gitlab v0.73.1 // 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
@@ -273,24 +269,24 @@ require (
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/atomic v1.10.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-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
go.uber.org/zap v1.22.0 // indirect
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
golang.org/x/tools v0.1.11 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/api v0.88.0 // indirect
google.golang.org/api v0.93.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f // indirect
google.golang.org/genproto v0.0.0-20220805133916-01dd62135a58 // indirect
google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
k8s.io/api v0.23.5 // indirect
@@ -299,7 +295,6 @@ require (
k8s.io/klog/v2 v2.60.1-0.20220317184644-43cc75f9ae89 // indirect
k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf // indirect
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.36.0 // indirect
modernc.org/ccgo/v3 v3.16.6 // indirect
@@ -311,7 +306,7 @@ require (
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.7.1 // indirect
sigs.k8s.io/release-utils v0.7.3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
@@ -321,8 +316,10 @@ 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-20220622213112-05595931fe9d // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
)
// Forked to remove https://github.com/rasky/go-lzo dependency, which is GPLv2 licensed.
replace github.com/CalebQ42/squashfs => github.com/sylabs/squashfs v0.5.5-0.20220526223455-67e0f4cd95c5
retract (
v0.53.2
v0.53.1 // Published accidentally with incorrect license in depdencies
)
+132 -253
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -45,7 +45,7 @@ func importProgress(source string) (*progress.Stage, *progress.Manual) {
return stage, prog
}
// nolint:funlen
//nolint:funlen
func (c *Client) Import(ctx context.Context, cfg ImportConfig) error {
stage, prog := importProgress(c.config.BaseURL)
+1 -1
View File
@@ -1,4 +1,4 @@
// nolint:dupl
//nolint:dupl
package anchore
import (
+1 -1
View File
@@ -1,4 +1,4 @@
// nolint: dupl
//nolint:dupl
package anchore
import (
+3 -1
View File
@@ -57,6 +57,7 @@ type Application struct {
Exclusions []string `yaml:"exclude" json:"exclude" mapstructure:"exclude"`
Attest attest `yaml:"attest" json:"attest" mapstructure:"attest"`
Platform string `yaml:"platform" json:"platform" mapstructure:"platform"`
ExternalSources ExternalSources `yaml:"external_sources" json:"external_sources" mapstructure:"external_sources"`
}
func (cfg Application) ToCatalogerConfig() cataloger.Config {
@@ -66,7 +67,8 @@ func (cfg Application) ToCatalogerConfig() cataloger.Config {
IncludeUnindexedArchives: cfg.Package.SearchUnindexedArchives,
Scope: cfg.Package.Cataloger.ScopeOpt,
},
Catalogers: cfg.Catalogers,
Catalogers: cfg.Catalogers,
ExternalSourcesEnabled: cfg.ExternalSources.ExternalSourcesEnabled,
}
}
+11
View File
@@ -0,0 +1,11 @@
package config
import "github.com/spf13/viper"
type ExternalSources struct {
ExternalSourcesEnabled bool `yaml:"external-sources-enabled" json:"external-sources-enabled" mapstructure:"external-sources-enabled"`
}
func (e ExternalSources) loadDefaultValues(v *viper.Viper) {
v.SetDefault("external-sources-enabled", false)
}
+1 -1
View File
@@ -30,7 +30,7 @@ func (cfg registry) loadDefaultValues(v *viper.Viper) {
v.SetDefault("registry.auth", []RegistryCredentials{})
}
// nolint:unparam
//nolint:unparam
func (cfg *registry) parseConfigValues() error {
// there may be additional credentials provided by env var that should be appended to the set of credentials
authority, username, password, token :=
+1 -1
View File
@@ -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.1"
JSONSchemaVersion = "3.3.2"
)
+2 -2
View File
@@ -2,7 +2,7 @@ package file
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/bmatcuk/doublestar/v4"
@@ -33,7 +33,7 @@ func ExtractGlobsFromTarToUniqueTempFile(archivePath, dir string, globs ...strin
// we have a file we want to extract....
tempfilePrefix := filepath.Base(filepath.Clean(file.Name())) + "-"
tempFile, err := ioutil.TempFile(dir, tempfilePrefix)
tempFile, err := os.CreateTemp(dir, tempfilePrefix)
if err != nil {
return fmt.Errorf("unable to create temp file: %w", err)
}
+1 -2
View File
@@ -4,7 +4,6 @@ import (
"archive/zip"
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
@@ -82,7 +81,7 @@ func ExtractFromZipToUniqueTempFile(archivePath, dir string, paths ...string) (m
visitor := func(file *zip.File) error {
tempfilePrefix := filepath.Base(filepath.Clean(file.Name)) + "-"
tempFile, err := ioutil.TempFile(dir, tempfilePrefix)
tempFile, err := os.CreateTemp(dir, tempfilePrefix)
if err != nil {
return fmt.Errorf("unable to create temp file: %w", err)
}
+2 -1
View File
@@ -95,7 +95,8 @@ type directoryEnd struct {
}
// note: this is derived from readDirectoryEnd within the archive/zip package
// nolint:gocognit
//
//nolint:gocognit
func findArchiveStartOffset(r io.ReaderAt, size int64) (startOfArchive uint64, err error) {
// look for directoryEndSignature in the last 1k, then in the last 65k
var buf []byte
+1 -1
View File
@@ -190,7 +190,7 @@ func DecodeInto(obj interface{}, values map[string]string, prefix string, fn Fie
decode(values, value, prefix, fn)
}
// nolint: funlen, gocognit, gocyclo
//nolint:funlen,gocognit,gocyclo
func decode(vals map[string]string, value reflect.Value, prefix string, fn FieldName) bool {
if !value.IsValid() || value.Type() == nil {
return false
@@ -112,8 +112,10 @@ func fileIDsForPackage(packageSpdxID string, relationships []artifact.Relationsh
continue
}
if string(relationship.From.ID()) == packageSpdxID {
fileIDs = append(fileIDs, string(relationship.To.ID()))
from := model.ElementID(relationship.From.ID()).String()
to := model.ElementID(relationship.To.ID()).String()
if from == packageSpdxID {
fileIDs = append(fileIDs, to)
}
}
return fileIDs
@@ -188,7 +188,7 @@ func Test_fileIDsForPackage(t *testing.T) {
}{
{
name: "find file IDs for packages with package-file relationships",
id: string(p.ID()),
id: model.ElementID(p.ID()).String(),
relationships: []artifact.Relationship{
{
From: p,
@@ -197,12 +197,12 @@ func Test_fileIDsForPackage(t *testing.T) {
},
},
expected: []string{
string(c.ID()),
model.ElementID(c.ID()).String(),
},
},
{
name: "ignore package-to-package",
id: string(p.ID()),
id: model.ElementID(p.ID()).String(),
relationships: []artifact.Relationship{
{
From: p,
@@ -214,7 +214,7 @@ func Test_fileIDsForPackage(t *testing.T) {
},
{
name: "ignore file-to-file",
id: string(p.ID()),
id: model.ElementID(p.ID()).String(),
relationships: []artifact.Relationship{
{
From: c,
@@ -226,7 +226,7 @@ func Test_fileIDsForPackage(t *testing.T) {
},
{
name: "ignore file-to-package",
id: string(p.ID()),
id: model.ElementID(p.ID()).String(),
relationships: []artifact.Relationship{
{
From: c,
@@ -238,7 +238,7 @@ func Test_fileIDsForPackage(t *testing.T) {
},
{
name: "filter by relationship type",
id: string(p.ID()),
id: model.ElementID(p.ID()).String(),
relationships: []artifact.Relationship{
{
From: p,
@@ -14,7 +14,8 @@ import (
)
// toFormatModel creates and populates a new JSON document struct that follows the SPDX 2.2 spec from the given cataloging results.
// nolint:funlen
//
//nolint:funlen
func toFormatModel(s sbom.SBOM) *spdx.Document2_2 {
name, namespace := spdxhelpers.DocumentNameAndNamespace(s.Source)
@@ -87,7 +88,8 @@ func toFormatModel(s sbom.SBOM) *spdx.Document2_2 {
}
// packages populates all Package Information from the package Catalog (see https://spdx.github.io/spdx-spec/3-package-information/)
// nolint: funlen
//
//nolint:funlen
func toFormatPackages(catalog *pkg.Catalog) map[spdx.ElementID]*spdx.Package2_2 {
results := make(map[spdx.ElementID]*spdx.Package2_2)
+15 -4
View File
@@ -2,6 +2,7 @@ package model
import (
"encoding/json"
"errors"
"fmt"
"github.com/anchore/syft/syft/source"
@@ -10,6 +11,8 @@ import (
"github.com/anchore/syft/syft/pkg"
)
var errUnknownMetadataType = errors.New("unknown metadata type")
// Package represents a pkg.Package object specialized for JSON marshaling and unmarshalling.
type Package struct {
PackageBasicData
@@ -60,13 +63,22 @@ func (p *Package) UnmarshalJSON(b []byte) error {
return err
}
return unpackMetadata(p, unpacker)
err := unpackMetadata(p, unpacker)
if errors.Is(err, errUnknownMetadataType) {
log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID)
return nil
}
return err
}
// nolint:funlen,gocognit,gocyclo
//nolint:funlen,gocognit,gocyclo
func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
p.MetadataType = unpacker.MetadataType
switch p.MetadataType {
case "":
// there is no metadata, skip
break
case pkg.AlpmMetadataType:
var payload pkg.AlpmMetadata
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
@@ -176,8 +188,7 @@ func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
}
p.Metadata = payload
default:
log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID)
return errUnknownMetadataType
}
return nil
}
+134 -12
View File
@@ -1,21 +1,95 @@
package model
import (
"testing"
"encoding/json"
"github.com/anchore/syft/syft/pkg"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)
func TestUnmarshalPackageGolang(t *testing.T) {
tests := []struct {
name string
p *Package
packageData []byte
assert func(*Package)
}{
{
name: "Package.UnmarshalJSON unmarshals PackageBasicData",
p: &Package{},
name: "unmarshal package metadata",
packageData: []byte(`{
"id": "8b594519bc23da50",
"name": "gopkg.in/square/go-jose.v2",
"version": "v2.6.0",
"type": "go-module",
"foundBy": "go-module-binary-cataloger",
"locations": [
{
"path": "/Users/hal/go/bin/syft"
}
],
"licenses": [],
"language": "go",
"cpes": [],
"purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0",
"metadataType": "GolangBinMetadata",
"metadata": {
"goCompiledVersion": "go1.18",
"architecture": "amd64",
"h1Digest": "h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI="
}
}`),
assert: func(p *Package) {
assert.NotNil(t, p.Metadata)
golangMetadata := p.Metadata.(pkg.GolangBinMetadata)
assert.NotEmpty(t, golangMetadata)
assert.Equal(t, "go1.18", golangMetadata.GoCompiledVersion)
},
},
{
name: "can handle package without metadata",
packageData: []byte(`{
"id": "8b594519bc23da50",
"name": "gopkg.in/square/go-jose.v2",
"version": "v2.6.0",
"type": "go-module",
"foundBy": "go-mod-cataloger",
"locations": [
{
"path": "/Users/hal/go/bin/syft"
}
],
"licenses": [],
"language": "go",
"cpes": [],
"purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0"
}`),
assert: func(p *Package) {
assert.Empty(t, p.MetadataType)
assert.Empty(t, p.Metadata)
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
p := &Package{}
err := p.UnmarshalJSON(test.packageData)
require.NoError(t, err)
test.assert(p)
})
}
}
func Test_unpackMetadata(t *testing.T) {
tests := []struct {
name string
packageData []byte
metadataType pkg.MetadataType
wantErr require.ErrorAssertionFunc
}{
{
name: "unmarshal package metadata",
metadataType: pkg.GolangBinMetadataType,
packageData: []byte(`{
"id": "8b594519bc23da50",
"name": "gopkg.in/square/go-jose.v2",
@@ -39,19 +113,67 @@ func TestUnmarshalPackageGolang(t *testing.T) {
}
}`),
},
{
name: "can handle package without metadata",
metadataType: "",
packageData: []byte(`{
"id": "8b594519bc23da50",
"name": "gopkg.in/square/go-jose.v2",
"version": "v2.6.0",
"type": "go-module",
"foundBy": "go-mod-cataloger",
"locations": [
{
"path": "/Users/hal/go/bin/syft"
}
],
"licenses": [],
"language": "go",
"cpes": [],
"purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0"
}`),
},
{
name: "bad metadata type is an error",
metadataType: "BOGOSITY",
wantErr: require.Error,
packageData: []byte(`{
"id": "8b594519bc23da50",
"name": "gopkg.in/square/go-jose.v2",
"version": "v2.6.0",
"type": "go-module",
"foundBy": "go-mod-cataloger",
"locations": [
{
"path": "/Users/hal/go/bin/syft"
}
],
"licenses": [],
"language": "go",
"cpes": [],
"purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0",
"metadataType": "BOGOSITY"
}`),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := test.p.UnmarshalJSON(test.packageData)
if err != nil {
t.Fatalf("could not unmarshal packageData: %v", err)
if test.wantErr == nil {
test.wantErr = require.NoError
}
p := &Package{}
assert.NotNil(t, test.p.Metadata)
golangMetadata := test.p.Metadata.(pkg.GolangBinMetadata)
assert.NotEmpty(t, golangMetadata)
assert.Equal(t, "go1.18", golangMetadata.GoCompiledVersion)
var basic PackageBasicData
require.NoError(t, json.Unmarshal(test.packageData, &basic))
p.PackageBasicData = basic
var unpacker packageMetadataUnpacker
require.NoError(t, json.Unmarshal(test.packageData, &unpacker))
err := unpackMetadata(p, unpacker)
assert.Equal(t, test.metadataType, p.MetadataType)
test.wantErr(t, err)
})
}
}
@@ -88,7 +88,7 @@
}
},
"schema": {
"version": "3.3.1",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json"
"version": "3.3.2",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.2.json"
}
}
@@ -184,7 +184,7 @@
}
},
"schema": {
"version": "3.3.1",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json"
"version": "3.3.2",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.2.json"
}
}
@@ -111,7 +111,7 @@
}
},
"schema": {
"version": "3.3.1",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json"
"version": "3.3.2",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.2.json"
}
}
+1 -2
View File
@@ -4,7 +4,6 @@ import (
"fmt"
"io"
"io/fs"
"io/ioutil"
"os"
"github.com/sirupsen/logrus"
@@ -55,7 +54,7 @@ func NewLogrusLogger(cfg LogrusConfig) *LogrusLogger {
}
output = logFile
default:
output = ioutil.Discard
output = io.Discard
}
appLogger.SetOutput(output)
+1 -1
View File
@@ -12,7 +12,7 @@ import (
// EX: gpl-2.0.0-only ---> GPL-2.0-only
// See the debian link for more details on the spdx license differences
//go:generate go run generate/generate_license_list.go
//go:generate go run ./generate
func ID(id string) (string, bool) {
value, exists := licenseIDs[strings.ToLower(id)]
+19 -4
View File
@@ -1,9 +1,9 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at 2022-08-02 12:46:45.90647 -0400 EDT m=+0.327870639
// This file was generated by robots at 2022-08-16 13:37:43.053262 -0400 EDT m=+0.183888850
// using data from https://spdx.org/licenses/licenses.json
package spdxlicense
const Version = "3.17"
const Version = "3.18"
var licenseIDs = map[string]string{
"0bsd": "0BSD",
@@ -201,16 +201,19 @@ var licenseIDs = map[string]string{
"cc-by-3": "CC-BY-3.0",
"cc-by-3-at": "CC-BY-3.0-AT",
"cc-by-3-de": "CC-BY-3.0-DE",
"cc-by-3-igo": "CC-BY-3.0-IGO",
"cc-by-3-nl": "CC-BY-3.0-NL",
"cc-by-3-us": "CC-BY-3.0-US",
"cc-by-3.0": "CC-BY-3.0",
"cc-by-3.0-at": "CC-BY-3.0-AT",
"cc-by-3.0-de": "CC-BY-3.0-DE",
"cc-by-3.0-igo": "CC-BY-3.0-IGO",
"cc-by-3.0-nl": "CC-BY-3.0-NL",
"cc-by-3.0-us": "CC-BY-3.0-US",
"cc-by-3.0.0": "CC-BY-3.0",
"cc-by-3.0.0-at": "CC-BY-3.0-AT",
"cc-by-3.0.0-de": "CC-BY-3.0-DE",
"cc-by-3.0.0-igo": "CC-BY-3.0-IGO",
"cc-by-3.0.0-nl": "CC-BY-3.0-NL",
"cc-by-3.0.0-us": "CC-BY-3.0-US",
"cc-by-4": "CC-BY-4.0",
@@ -614,7 +617,6 @@ var licenseIDs = map[string]string{
"jasper-2.0.0": "JasPer-2.0",
"jpnic": "JPNIC",
"json": "JSON",
"kicad-libraries-exception": "KiCad-libraries-exception",
"lal-1": "LAL-1.2",
"lal-1.2": "LAL-1.2",
"lal-1.2.0": "LAL-1.2",
@@ -622,7 +624,7 @@ var licenseIDs = map[string]string{
"lal-1.3.0": "LAL-1.3",
"latex2e": "Latex2e",
"leptonica": "Leptonica",
"lgpl-2": "LGPL-2.1-only",
"lgpl-2": "LGPL-2.0-only",
"lgpl-2+": "LGPL-2.0-or-later",
"lgpl-2-only": "LGPL-2.0-only",
"lgpl-2-or-later": "LGPL-2.0-or-later",
@@ -692,7 +694,14 @@ var licenseIDs = map[string]string{
"lppl-1.3c": "LPPL-1.3c",
"lppl-1a": "LPPL-1.3a",
"lppl-1c": "LPPL-1.3c",
"lzma-sdk-9": "LZMA-SDK-9.22",
"lzma-sdk-9-to-9.20": "LZMA-SDK-9.11-to-9.20",
"lzma-sdk-9.11-to-9.20": "LZMA-SDK-9.11-to-9.20",
"lzma-sdk-9.11.0-to-9.20": "LZMA-SDK-9.11-to-9.20",
"lzma-sdk-9.22": "LZMA-SDK-9.22",
"lzma-sdk-9.22.0": "LZMA-SDK-9.22",
"makeindex": "MakeIndex",
"minpack": "Minpack",
"miros": "MirOS",
"mit": "MIT",
"mit-0": "MIT-0",
@@ -704,6 +713,7 @@ var licenseIDs = map[string]string{
"mit-open-group": "MIT-open-group",
"mitnfa": "MITNFA",
"motosoto": "Motosoto",
"mpi-permissive": "mpi-permissive",
"mpich2": "mpich2",
"mpl-1": "MPL-1.0",
"mpl-1.0": "MPL-1.0",
@@ -717,6 +727,7 @@ var licenseIDs = map[string]string{
"mpl-2.0.0": "MPL-2.0",
"mpl-2.0.0-no-copyleft-exception": "MPL-2.0-no-copyleft-exception",
"mplus": "mplus",
"ms-lpl": "MS-LPL",
"ms-pl": "MS-PL",
"ms-rl": "MS-RL",
"mtll": "MTLL",
@@ -746,6 +757,9 @@ var licenseIDs = map[string]string{
"netcdf": "NetCDF",
"newsletr": "Newsletr",
"ngpl": "NGPL",
"nicta-1": "NICTA-1.0",
"nicta-1.0": "NICTA-1.0",
"nicta-1.0.0": "NICTA-1.0",
"nist-pd": "NIST-PD",
"nist-pd-fallback": "NIST-PD-fallback",
"nlod-1": "NLOD-1.0",
@@ -902,6 +916,7 @@ var licenseIDs = map[string]string{
"python-2": "Python-2.0",
"python-2.0": "Python-2.0",
"python-2.0.0": "Python-2.0",
"python-2.0.1": "Python-2.0.1",
"qhull": "Qhull",
"qpl-1": "QPL-1.0",
"qpl-1.0": "QPL-1.0",
+2 -2
View File
@@ -2,7 +2,7 @@ package version
import (
"fmt"
"io/ioutil"
"io"
"net/http"
"strings"
@@ -59,7 +59,7 @@ func fetchLatestApplicationVersion() (*hashiVersion.Version, error) {
return nil, fmt.Errorf("HTTP %d on fetching latest version: %s", resp.StatusCode, resp.Status)
}
versionBytes, err := ioutil.ReadAll(resp.Body)
versionBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read latest version: %w", err)
}
+2 -2
View File
@@ -4,7 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"os"
"reflect"
"sort"
@@ -118,7 +118,7 @@ func write(schema []byte) {
panic(err)
}
existingSchemaBytes, err := ioutil.ReadAll(existingFh)
existingSchemaBytes, err := io.ReadAll(existingFh)
if err != nil {
panic(err)
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -13,7 +13,7 @@ const (
// PackageCatalogerStarted is a partybus event that occurs when the package cataloging has begun
PackageCatalogerStarted partybus.EventType = "syft-package-cataloger-started-event"
// nolint:gosec
//nolint:gosec
// SecretsCatalogerStarted is a partybus event that occurs when the secrets cataloging has begun
SecretsCatalogerStarted partybus.EventType = "syft-secrets-cataloger-started-event"
+20 -19
View File
@@ -3,9 +3,9 @@ Package syft is a "one-stop-shop" for helper utilities for all major functionali
Here is what the main execution path for syft does:
1. Parse a user image string to get a stereoscope image.Source object
2. Invoke all catalogers to catalog the image, adding discovered packages to a single catalog object
3. Invoke one or more encoders to output contents of the catalog
1. Parse a user image string to get a stereoscope image.Source object
2. Invoke all catalogers to catalog the image, adding discovered packages to a single catalog object
3. Invoke one or more encoders to output contents of the catalog
A Source object encapsulates the image object to be cataloged and the user options (catalog all layers vs. squashed layer),
providing a way to inspect paths and file content within the image. The Source object, not the image object, is used
@@ -48,24 +48,25 @@ func CatalogPackages(src *source.Source, cfg cataloger.Config) (*pkg.Catalog, []
log.Info("could not identify distro")
}
// conditionally use the correct set of loggers based on the input type (container image or directory)
// if the catalogers have been configured, use them regardless of input type
var catalogers []cataloger.Cataloger
switch src.Metadata.Scheme {
case source.ImageScheme:
log.Info("cataloging image")
catalogers = cataloger.ImageCatalogers(cfg)
case source.FileScheme:
log.Info("cataloging file")
catalogers = cataloger.AllCatalogers(cfg)
case source.DirectoryScheme:
log.Info("cataloging directory")
catalogers = cataloger.DirectoryCatalogers(cfg)
default:
return nil, nil, nil, fmt.Errorf("unable to determine cataloger set from scheme=%+v", src.Metadata.Scheme)
}
if cataloger.RequestedAllCatalogers(cfg) {
if len(cfg.Catalogers) > 0 {
catalogers = cataloger.AllCatalogers(cfg)
} else {
// otherwise conditionally use the correct set of loggers based on the input type (container image or directory)
switch src.Metadata.Scheme {
case source.ImageScheme:
log.Info("cataloging image")
catalogers = cataloger.ImageCatalogers(cfg)
case source.FileScheme:
log.Info("cataloging file")
catalogers = cataloger.AllCatalogers(cfg)
case source.DirectoryScheme:
log.Info("cataloging directory")
catalogers = cataloger.DirectoryCatalogers(cfg)
default:
return nil, nil, nil, fmt.Errorf("unable to determine cataloger set from scheme=%+v", src.Metadata.Scheme)
}
}
catalog, relationships, err := cataloger.Catalog(resolver, release, catalogers...)
+2 -2
View File
@@ -2,7 +2,7 @@ package linux
import (
"fmt"
"io/ioutil"
"io"
"regexp"
"strings"
@@ -68,7 +68,7 @@ func IdentifyRelease(resolver source.FileResolver) *Release {
continue
}
content, err := ioutil.ReadAll(contentReader)
content, err := io.ReadAll(contentReader)
internal.CloseAndLogError(contentReader, location.VirtualPath)
if err != nil {
log.Warnf("unable to read %q: %+v", location.RealPath, err)
+5
View File
@@ -23,6 +23,11 @@ func (c *Cataloger) Name() string {
return catalogerName
}
// UsesExternalSources indicates that the alpmdb cataloger does not use external sources
func (c *Cataloger) UsesExternalSources() bool {
return false
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation.
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
fileMatches, err := resolver.FilesByGlob(pkg.AlpmDBGlob)
+1 -1
View File
@@ -75,7 +75,7 @@ func getFileReader(path string, resolver source.FileResolver) (io.Reader, error)
return dbContentReader, nil
}
// nolint:funlen
//nolint:funlen
func parseDatabase(b *bufio.Scanner) (*pkg.AlpmMetadata, error) {
var entry pkg.AlpmMetadata
var err error
+2 -1
View File
@@ -74,8 +74,9 @@ func parseApkDB(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relation
return packages, nil, nil
}
// nolint:funlen
// parseApkDBEntry reads and parses a single pkg.ApkMetadata element from the stream, returning nil if their are no more entries.
//
//nolint:funlen
func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) {
var entry pkg.ApkMetadata
pkgFields := make(map[string]interface{})
+16 -9
View File
@@ -110,29 +110,36 @@ func packageFileOwnershipRelationships(p pkg.Package, resolver source.FilePathRe
return nil, nil
}
var relationships []artifact.Relationship
locations := map[artifact.ID]source.Location{}
for _, path := range fileOwner.OwnedFiles() {
locations, err := resolver.FilesByPath(path)
pathRefs, err := resolver.FilesByPath(path)
if err != nil {
return nil, fmt.Errorf("unable to find path for path=%q: %w", path, err)
}
if len(locations) == 0 {
if len(pathRefs) == 0 {
// ideally we want to warn users about missing files from a package, however, it is very common for
// container image authors to delete files that are not needed in order to keep image sizes small. Adding
// a warning here would be needlessly noisy (even for popular base images).
continue
}
for _, l := range locations {
relationships = append(relationships, artifact.Relationship{
From: p,
To: l.Coordinates,
Type: artifact.ContainsRelationship,
})
for _, ref := range pathRefs {
if oldRef, ok := locations[ref.Coordinates.ID()]; ok {
log.Debugf("found path duplicate of %s", oldRef.RealPath)
}
locations[ref.Coordinates.ID()] = ref
}
}
var relationships []artifact.Relationship
for _, location := range locations {
relationships = append(relationships, artifact.Relationship{
From: p,
To: location.Coordinates,
Type: artifact.ContainsRelationship,
})
}
return relationships, nil
}
+38 -7
View File
@@ -41,6 +41,8 @@ type Cataloger interface {
Name() string
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing the catalog source.
Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error)
// UsesExternalSources returns if the cataloger uses external sources, such as querying a database
UsesExternalSources() bool
}
// ImageCatalogers returns a slice of locally implemented catalogers that are fit for detecting installations of packages.
@@ -58,7 +60,7 @@ func ImageCatalogers(cfg Config) []Cataloger {
golang.NewGoModuleBinaryCataloger(),
dotnet.NewDotnetDepsCataloger(),
portage.NewPortageCataloger(),
}, cfg.Catalogers)
}, cfg)
}
// DirectoryCatalogers returns a slice of locally implemented catalogers that are fit for detecting packages from index files (and select installations)
@@ -84,7 +86,7 @@ func DirectoryCatalogers(cfg Config) []Cataloger {
cpp.NewConanfileCataloger(),
portage.NewPortageCataloger(),
haskell.NewHackageCataloger(),
}, cfg.Catalogers)
}, cfg)
}
// AllCatalogers returns all implemented catalogers
@@ -114,10 +116,20 @@ func AllCatalogers(cfg Config) []Cataloger {
cpp.NewConanfileCataloger(),
portage.NewPortageCataloger(),
haskell.NewHackageCataloger(),
}, cfg.Catalogers)
}, cfg)
}
// RequestedAllCatalogers returns true if all Catalogers have been requested. Takes into account cfg.ExternalSourcesEnabled
func RequestedAllCatalogers(cfg Config) bool {
// if external sources are disabled, only return false if there actually are any catalogers that use external sources
if !cfg.ExternalSourcesEnabled {
for _, cat := range AllCatalogers(Config{Catalogers: []string{"all"}, ExternalSourcesEnabled: true}) {
if cat.UsesExternalSources() {
return false
}
}
}
for _, enableCatalogerPattern := range cfg.Catalogers {
if enableCatalogerPattern == AllCatalogersPattern {
return true
@@ -126,14 +138,33 @@ func RequestedAllCatalogers(cfg Config) bool {
return false
}
func filterCatalogers(catalogers []Cataloger, enabledCatalogerPatterns []string) []Cataloger {
func filterForExternalSources(catalogers []Cataloger, cfg Config) []Cataloger {
if cfg.ExternalSourcesEnabled {
return catalogers
}
var enabledCatalogers []Cataloger
for _, cataloger := range catalogers {
if !cataloger.UsesExternalSources() {
enabledCatalogers = append(enabledCatalogers, cataloger)
} else {
log.Infof("cataloger %v will not be used because external sources are disabled", cataloger.Name())
}
}
return enabledCatalogers
}
func filterCatalogers(catalogers []Cataloger, cfg Config) []Cataloger {
enabledCatalogerPatterns := cfg.Catalogers
// if cataloger is not set, all applicable catalogers are enabled by default
if len(enabledCatalogerPatterns) == 0 {
return catalogers
return filterForExternalSources(catalogers, cfg)
}
for _, enableCatalogerPattern := range enabledCatalogerPatterns {
if enableCatalogerPattern == AllCatalogersPattern {
return catalogers
return filterForExternalSources(catalogers, cfg)
}
}
var keepCatalogers []Cataloger
@@ -144,7 +175,7 @@ func filterCatalogers(catalogers []Cataloger, enabledCatalogerPatterns []string)
}
log.Infof("skipping cataloger %q", cataloger.Name())
}
return keepCatalogers
return filterForExternalSources(keepCatalogers, cfg)
}
func contains(enabledPartial []string, catalogerName string) bool {
+28 -6
View File
@@ -1,11 +1,12 @@
package cataloger
import (
"testing"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
"github.com/stretchr/testify/assert"
"testing"
)
var _ Cataloger = (*dummy)(nil)
@@ -22,12 +23,17 @@ func (d dummy) Catalog(_ source.FileResolver) ([]pkg.Package, []artifact.Relatio
panic("not implemented")
}
func (d dummy) UsesExternalSources() bool {
return false
}
func Test_filterCatalogers(t *testing.T) {
tests := []struct {
name string
patterns []string
catalogers []string
want []string
name string
patterns []string
ExternalSourcesEnabled bool
catalogers []string
want []string
}{
{
name: "no filtering",
@@ -142,6 +148,21 @@ func Test_filterCatalogers(t *testing.T) {
"go-module-binary-cataloger",
},
},
{ // Note: no catalogers with external sources are currently implemented
name: "external sources enabled",
patterns: []string{"all"},
ExternalSourcesEnabled: true,
catalogers: []string{
"ruby-gemspec-cataloger",
"python-package-cataloger",
"rekor-cataloger",
},
want: []string{
"ruby-gemspec-cataloger",
"python-package-cataloger",
"rekor-cataloger",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -149,7 +170,8 @@ func Test_filterCatalogers(t *testing.T) {
for _, n := range tt.catalogers {
catalogers = append(catalogers, dummy{name: n})
}
got := filterCatalogers(catalogers, tt.patterns)
cfg := Config{Catalogers: tt.patterns, ExternalSourcesEnabled: tt.ExternalSourcesEnabled}
got := filterCatalogers(catalogers, cfg)
var gotNames []string
for _, g := range got {
gotNames = append(gotNames, g.Name())
+18 -3
View File
@@ -6,10 +6,9 @@ package common
import (
"fmt"
"github.com/anchore/syft/syft/artifact"
"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/source"
)
@@ -19,14 +18,18 @@ import (
type GenericCataloger struct {
globParsers map[string]ParserFn
pathParsers map[string]ParserFn
postProcessors []PostProcessFunc
upstreamCataloger string
}
type PostProcessFunc func(resolver source.FileResolver, location source.Location, p *pkg.Package) error
// NewGenericCataloger if provided path-to-parser-function and glob-to-parser-function lookups creates a GenericCataloger
func NewGenericCataloger(pathParsers map[string]ParserFn, globParsers map[string]ParserFn, upstreamCataloger string) *GenericCataloger {
func NewGenericCataloger(pathParsers map[string]ParserFn, globParsers map[string]ParserFn, upstreamCataloger string, postProcessors ...PostProcessFunc) *GenericCataloger {
return &GenericCataloger{
globParsers: globParsers,
pathParsers: pathParsers,
postProcessors: postProcessors,
upstreamCataloger: upstreamCataloger,
}
}
@@ -36,6 +39,11 @@ func (c *GenericCataloger) Name() string {
return c.upstreamCataloger
}
// UsesExternalSources indicates that any GenericCatalogor does not use external sources
func (c *GenericCataloger) UsesExternalSources() bool {
return false
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing the catalog source.
func (c *GenericCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
var packages []pkg.Package
@@ -69,6 +77,13 @@ func (c *GenericCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package,
continue
}
for _, postProcess := range c.postProcessors {
err = postProcess(resolver, location, p)
if err != nil {
return nil, nil, err
}
}
packages = append(packages, *p)
}
+3 -2
View File
@@ -5,8 +5,9 @@ import (
)
type Config struct {
Search SearchConfig
Catalogers []string
Search SearchConfig
Catalogers []string
ExternalSourcesEnabled bool
}
func DefaultConfig() Config {
+5
View File
@@ -36,6 +36,11 @@ func (c *Cataloger) Name() string {
return "dpkgdb-cataloger"
}
// UsesExternalSources indicates that the dpkgdb cataloger does not use external sources
func (c *Cataloger) UsesExternalSources() bool {
return false
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing dpkg support files.
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
dbFileMatches, err := resolver.FilesByGlob(pkg.DpkgDBGlob)
@@ -28,6 +28,11 @@ func (c *Cataloger) Name() string {
return catalogerName
}
// UsesExternalSources indicates that the golang binary cataloger does not use external sources
func (c *Cataloger) UsesExternalSources() bool {
return false
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation.
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
var pkgs []pkg.Package
+1 -2
View File
@@ -3,7 +3,6 @@ package golang
import (
"fmt"
"io"
"io/ioutil"
"sort"
"github.com/anchore/syft/syft/artifact"
@@ -15,7 +14,7 @@ import (
func parseGoMod(path string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
packages := make(map[string]*pkg.Package)
contents, err := ioutil.ReadAll(reader)
contents, err := io.ReadAll(reader)
if err != nil {
return nil, nil, fmt.Errorf("failed to read go module: %w", err)
}
@@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
macho "github.com/anchore/go-macholibre"
"github.com/anchore/syft/internal/log"
@@ -45,7 +44,7 @@ func GetUnionReader(readerCloser io.ReadCloser) (UnionReader, error) {
return reader, nil
}
b, err := ioutil.ReadAll(readerCloser)
b, err := io.ReadAll(readerCloser)
if err != nil {
return nil, fmt.Errorf("unable to read contents from binary: %w", err)
}
+21 -10
View File
@@ -36,18 +36,20 @@ import (
// This match group covers the "version-indicating" patterns mentioned in the above description. Given the pipes (
// '|'), this functions as a series of 'OR'-joined conditions:
//
// \d.* ... "If it starts with a numeric digit, this is a version, no matter what follows."
// build\d*.* ... "If it starts with "build" and then a numeric digit immediately after, this is a version."
// rc?\d+(?:^[[:alpha:]].*)? ... "If it starts with "r" or "rc" and then one or more numeric digits immediately
// after, but no alpha characters right after that (in the same word), this is a version."
// \d.* ... "If it starts with a numeric digit, this is a version, no matter what follows."
// build\d*.* ... "If it starts with "build" and then a numeric digit immediately after, this is a version."
// rc?\d+(?:^[[:alpha:]].*)? ... "If it starts with "r" or "rc" and then one or more numeric digits immediately
// after, but no alpha characters right after that (in the same word), this is a version."
//
// Match examples:
// some-package-4.0.1 --> name="some-package", version="4.0.1"
// prefix.thing-4 --> name="prefix.thing", version="4"
// my-http2-server-5 --> name="my-http2-server", version="5"
// jetpack-build235-rc5 --> name="jetpack", version="build2.0-rc5"
// ironman-r4-2009 --> name="ironman", version="r4-2009"
var nameAndVersionPattern = regexp.MustCompile(`(?Ui)^(?P<name>(?:[[:alpha:]][[:word:].]*(?:\.[[:alpha:]][[:word:].]*)*-?)+)(?:-(?P<version>(?:\d.*|(?:build\d*.*)|(?:rc?\d+(?:^[[:alpha:]].*)?))))?$`)
//
// some-package-4.0.1 --> name="some-package", version="4.0.1"
// prefix.thing-4 --> name="prefix.thing", version="4"
// my-http2-server-5 --> name="my-http2-server", version="5"
// jetpack-build235-rc5 --> name="jetpack", version="build2.0-rc5"
// ironman-r4-2009 --> name="ironman", version="r4-2009"
var nameAndVersionPattern = regexp.MustCompile(`(?Ui)^(?P<name>(?:[[:alpha:]][[:word:].]*(?:\.[[:alpha:]][[:word:].]*)*-?)+)(?:-(?P<version>(\d.*|(build\d*.*)|(rc?\d+(?:^[[:alpha:]].*)?))))?$`)
var secondaryVersionPattern = regexp.MustCompile(`(?:[._-](?P<version>(\d.*|(build\d*.*)|(rc?\d+(?:^[[:alpha:]].*)?))))?$`)
type archiveFilename struct {
raw string
@@ -85,6 +87,15 @@ func newJavaArchiveFilename(raw string) archiveFilename {
name := getSubexp(matches, "name", nameAndVersionPattern, raw)
version := getSubexp(matches, "version", nameAndVersionPattern, raw)
// some jars get named with different conventions, like `_<version>` or `.<version>`
if version == "" {
matches = secondaryVersionPattern.FindStringSubmatch(name)
version = getSubexp(matches, "version", secondaryVersionPattern, raw)
if version != "" {
name = name[0 : len(name)-len(version)-1]
}
}
return archiveFilename{
raw: raw,
name: name,
@@ -22,6 +22,20 @@ func TestExtractInfoFromJavaArchiveFilename(t *testing.T) {
name: "pkg-maven",
ty: pkg.UnknownPkg,
},
{
filename: "pkg-maven.4.3.2.blerg",
version: "4.3.2",
extension: "blerg",
name: "pkg-maven",
ty: pkg.UnknownPkg,
},
{
filename: "pkg-maven_4.3.2.blerg",
version: "4.3.2",
extension: "blerg",
name: "pkg-maven",
ty: pkg.UnknownPkg,
},
{
filename: "pkg-maven-4.3.2.jar",
version: "4.3.2",
+17 -15
View File
@@ -104,27 +104,29 @@ func TestParseJar(t *testing.T) {
Manifest: &pkg.JavaManifest{
Main: map[string]string{
"Manifest-Version": "1.0",
"Specification-Title": "The Jenkins Plugins Parent POM Project",
"Implementation-Title": "example-jenkins-plugin",
"Specification-Title": "Example Jenkins Plugin",
"Specification-Version": "1.0",
"Implementation-Title": "Example Jenkins Plugin",
"Implementation-Version": "1.0-SNAPSHOT",
// extra fields...
"Archiver-Version": "Plexus Archiver",
//"Archiver-Version": "Plexus Archiver",
"Plugin-License-Url": "https://opensource.org/licenses/MIT",
"Plugin-License-Name": "MIT License",
"Created-By": "Apache Maven",
"Created-By": "Maven Archiver 3.6.0",
//"Built-By": "?",
//"Build-Jdk": "14.0.1",
"Jenkins-Version": "2.164.3",
"Minimum-Java-Version": "1.8",
"Plugin-Developers": "",
"Plugin-ScmUrl": "https://github.com/jenkinsci/plugin-pom/example-jenkins-plugin",
"Extension-Name": "example-jenkins-plugin",
"Short-Name": "example-jenkins-plugin",
"Group-Id": "io.jenkins.plugins",
"Plugin-Dependencies": "structs:1.20",
"Build-Jdk-Spec": "18",
"Jenkins-Version": "2.204",
//"Minimum-Java-Version": "1.8",
"Plugin-Developers": "",
"Plugin-ScmUrl": "https://github.com/jenkinsci/plugin-pom/example-jenkins-plugin",
//"Extension-Name": "example-jenkins-plugin",
"Short-Name": "example-jenkins-plugin",
"Group-Id": "io.jenkins.plugins",
"Plugin-Dependencies": "structs:1.20",
//"Plugin-Version": "1.0-SNAPSHOT (private-07/09/2020 13:30-?)",
"Hudson-Version": "2.164.3",
"Long-Name": "TODO Plugin",
"Hudson-Version": "2.204",
"Long-Name": "Example Jenkins Plugin",
},
},
PomProperties: &pkg.PomProperties{
@@ -180,7 +182,7 @@ func TestParseJar(t *testing.T) {
"Manifest-Version": "1.0",
// extra fields...
"Archiver-Version": "Plexus Archiver",
"Created-By": "Apache Maven 3.6.3",
"Created-By": "Apache Maven 3.8.6",
//"Built-By": "?",
//"Build-Jdk": "14.0.1",
"Main-Class": "hello.HelloWorld",
@@ -14,9 +14,10 @@ import (
const manifestGlob = "/META-INF/MANIFEST.MF"
// nolint:funlen
// parseJavaManifest takes MANIFEST.MF file content and returns sections of parsed key/value pairs.
// For more information: https://docs.oracle.com/en/java/javase/11/docs/specs/jar/jar.html#jar-manifest
//
//nolint:funlen
func parseJavaManifest(path string, reader io.Reader) (*pkg.JavaManifest, error) {
var manifest pkg.JavaManifest
var sections []map[string]string
@@ -4,7 +4,7 @@ set -uxe
# note: this can be easily done in a 1-liner, however circle CI does NOT allow volume mounts from the host in docker executors (since they are on remote hosts, where the host files are inaccessible)
PKGSDIR=$1
CTRID=$(docker create -u "$(id -u):$(id -g)" -e MAVEN_CONFIG=/tmp/.m2 -v /example-java-app -w /example-java-app maven:3.6.3-openjdk-14 mvn -Duser.home=/tmp -DskipTests package)
CTRID=$(docker create -u "$(id -u):$(id -g)" -e MAVEN_CONFIG=/tmp/.m2 -v /example-java-app -w /example-java-app maven:3.8.6-openjdk-18 mvn -Duser.home=/tmp -DskipTests package)
function cleanup() {
docker rm "${CTRID}"
@@ -16,4 +16,4 @@ set +e
docker cp "$(pwd)/example-java-app" "${CTRID}:/"
docker start -a "${CTRID}"
mkdir -p "$PKGSDIR"
docker cp "${CTRID}:/example-java-app/target/example-java-app-maven-0.1.0.jar" "$PKGSDIR"
docker cp "${CTRID}:/example-java-app/target/example-java-app-maven-0.1.0.jar" "$PKGSDIR"
@@ -4,7 +4,7 @@ set -uxe
# note: this can be easily done in a 1-liner, however circle CI does NOT allow volume mounts from the host in docker executors (since they are on remote hosts, where the host files are inaccessible)
PKGSDIR=$1
CTRID=$(docker create -u "$(id -u):$(id -g)" -e MAVEN_CONFIG=/tmp/.m2 -v /example-jenkins-plugin -w /example-jenkins-plugin maven:3.6.3-openjdk-14 mvn -Duser.home=/tmp -DskipTests package)
CTRID=$(docker create -u "$(id -u):$(id -g)" -e MAVEN_CONFIG=/tmp/.m2 -v /example-jenkins-plugin -w /example-jenkins-plugin maven:3.8.6-openjdk-18 mvn -Duser.home=/tmp -DskipTests package)
function cleanup() {
docker rm "${CTRID}"
@@ -17,4 +17,4 @@ docker cp "$(pwd)/example-jenkins-plugin" "${CTRID}:/"
docker start -a "${CTRID}"
mkdir -p "$PKGSDIR"
docker cp "${CTRID}:/example-jenkins-plugin/target/example-jenkins-plugin.hpi" "$PKGSDIR"
docker cp "${CTRID}:/example-jenkins-plugin/target/example-jenkins-plugin.jar" "$PKGSDIR"
docker cp "${CTRID}:/example-jenkins-plugin/target/example-jenkins-plugin.jar" "$PKGSDIR"
@@ -4,7 +4,7 @@ set -uxe
# note: this can be easily done in a 1-liner, however circle CI does NOT allow volume mounts from the host in docker executors (since they are on remote hosts, where the host files are inaccessible)
PKGSDIR=$1
CTRID=$(docker create -u "$(id -u):$(id -g)" -e MAVEN_CONFIG=/tmp/.m2 -v /example-sb-app -w /example-sb-app maven:3.6.3-openjdk-14 mvn -Duser.home=/tmp -DskipTests package spring-boot:repackage)
CTRID=$(docker create -u "$(id -u):$(id -g)" -e MAVEN_CONFIG=/tmp/.m2 -v /example-sb-app -w /example-sb-app maven:3.8.6-openjdk-18 mvn -Duser.home=/tmp -DskipTests package spring-boot:repackage)
function cleanup() {
docker rm "${CTRID}"
@@ -16,4 +16,4 @@ set +e
docker cp "$(pwd)/example-sb-app" "${CTRID}:/"
docker start -a "${CTRID}"
mkdir -p "$PKGSDIR"
docker cp "${CTRID}:/example-sb-app/target/spring-boot-0.0.1-SNAPSHOT.jar" "$PKGSDIR"
docker cp "${CTRID}:/example-sb-app/target/spring-boot-0.0.1-SNAPSHOT.jar" "$PKGSDIR"
@@ -4,7 +4,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>3.50</version>
<version>4.46</version>
<relativePath />
</parent>
<groupId>io.jenkins.plugins</groupId>
@@ -13,7 +13,7 @@
<packaging>hpi</packaging>
<properties>
<!-- Baseline Jenkins version you use to build the plugin. Users must have this version or newer to run. -->
<jenkins.version>2.164.3</jenkins.version>
<jenkins.version>2.204</jenkins.version>
<java.level>8</java.level>
<!-- Other properties you may want to use:
~ jenkins-test-harness.version: Jenkins Test Harness version you use to test the plugin. For Jenkins version >= 1.580.1 use JTH 2.0 or higher.
@@ -21,7 +21,7 @@
~ stapler-plugin.version: The Stapler Maven plugin version required by the plugin.
-->
</properties>
<name>TODO Plugin</name>
<name>Example Jenkins Plugin</name>
<!-- The default licence for Jenkins OSS Plugins is MIT. Substitute for the applicable one if needed. -->
<licenses>
<license>
+58 -1
View File
@@ -4,7 +4,15 @@ Package javascript provides a concrete Cataloger implementation for JavaScript e
package javascript
import (
"encoding/json"
"io"
"path"
"strings"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/common"
"github.com/anchore/syft/syft/source"
)
// NewJavascriptPackageCataloger returns a new JavaScript cataloger object based on detection of npm based packages.
@@ -21,7 +29,56 @@ func NewJavascriptLockCataloger() *common.GenericCataloger {
globParsers := map[string]common.ParserFn{
"**/package-lock.json": parsePackageLock,
"**/yarn.lock": parseYarnLock,
"**/pnpm-lock.yaml": parsePnpmLock,
}
return common.NewGenericCataloger(nil, globParsers, "javascript-lock-cataloger")
return common.NewGenericCataloger(nil, globParsers, "javascript-lock-cataloger", addLicenses)
}
func addLicenses(resolver source.FileResolver, location source.Location, p *pkg.Package) error {
dir := path.Dir(location.RealPath)
pkgPath := []string{dir, "node_modules"}
pkgPath = append(pkgPath, strings.Split(p.Name, "/")...)
pkgPath = append(pkgPath, "package.json")
pkgFile := path.Join(pkgPath...)
locations, err := resolver.FilesByPath(pkgFile)
if err != nil {
log.Debugf("an error occurred attempting to read: %s - %+v", pkgFile, err)
return nil
}
if len(locations) == 0 {
return nil
}
for _, location := range locations {
contentReader, err := resolver.FileContentsByLocation(location)
if err != nil {
log.Debugf("error getting file content reader for %s: %v", pkgFile, err)
return nil
}
contents, err := io.ReadAll(contentReader)
if err != nil {
log.Debugf("error reading file contents for %s: %v", pkgFile, err)
return nil
}
var pkgJSON packageJSON
err = json.Unmarshal(contents, &pkgJSON)
if err != nil {
log.Debugf("error parsing %s: %v", pkgFile, err)
return nil
}
licenses, err := pkgJSON.licensesFromJSON()
if err != nil {
log.Debugf("error getting licenses from %s: %v", pkgFile, err)
return nil
}
p.Licenses = append(p.Licenses, licenses...)
}
return nil
}
@@ -0,0 +1,102 @@
package javascript
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
func Test_JavascriptCataloger(t *testing.T) {
expected := map[string]pkg.Package{
"@actions/core": {
Name: "@actions/core",
Version: "1.6.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Licenses: []string{"MIT"},
},
"wordwrap": {
Name: "wordwrap",
Version: "0.0.3",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"get-stdin": {
Name: "get-stdin",
Version: "5.0.1",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"minimist": {
Name: "minimist",
Version: "0.0.10",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"optimist": {
Name: "optimist",
Version: "0.6.1",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"string-width": {
Name: "string-width",
Version: "2.1.1",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"strip-ansi": {
Name: "strip-ansi",
Version: "4.0.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"strip-eof": {
Name: "wordwrap",
Version: "1.0.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"ansi-regex": {
Name: "ansi-regex",
Version: "3.0.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"is-fullwidth-code-point": {
Name: "is-fullwidth-code-point",
Version: "2.0.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"cowsay": {
Name: "cowsay",
Version: "1.4.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Licenses: []string{"MIT"},
},
}
s, err := source.NewFromDirectory("test-fixtures/pkg-lock")
require.NoError(t, err)
resolver, err := s.FileResolver(source.AllLayersScope)
require.NoError(t, err)
actual, _, err := NewJavascriptLockCataloger().Catalog(resolver)
if err != nil {
t.Fatalf("failed to parse package-lock.json: %+v", err)
}
var pkgs []*pkg.Package
for _, p := range actual {
p2 := p
pkgs = append(pkgs, &p2)
}
assertPkgsEqual(t, pkgs, expected)
}
@@ -33,6 +33,7 @@ type packageJSON struct {
Description string `json:"description"`
Dependencies map[string]string `json:"dependencies"`
Repository repository `json:"repository"`
Private bool `json:"private"`
}
type author struct {
@@ -217,6 +218,7 @@ func newPackageJSONPackage(p packageJSON) *pkg.Package {
Homepage: p.Homepage,
URL: p.Repository.URL,
Licenses: licenses,
Private: p.Private,
},
}
}
@@ -147,6 +147,26 @@ func TestParsePackageJSON(t *testing.T) {
},
},
},
{
Fixture: "test-fixtures/pkg-json/package-private.json",
ExpectedPkg: pkg.Package{
Name: "npm",
Version: "6.14.6",
Type: pkg.NpmPkg,
Licenses: []string{"Artistic-2.0"},
Language: pkg.JavaScript,
MetadataType: pkg.NpmPackageJSONMetadataType,
Metadata: pkg.NpmPackageJSONMetadata{
Name: "npm",
Version: "6.14.6",
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
Homepage: "https://docs.npmjs.com/",
URL: "https://github.com/npm/cli",
Licenses: []string{"Artistic-2.0"},
Private: true,
},
},
},
}
for _, test := range tests {
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io"
"strings"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
@@ -18,6 +19,7 @@ type PackageLock struct {
Requires bool `json:"requires"`
LockfileVersion int `json:"lockfileVersion"`
Dependencies map[string]Dependency
Packages map[string]Package
}
// Dependency represents a single package dependency listed in the package.lock json file
@@ -25,7 +27,13 @@ type Dependency struct {
Version string `json:"version"`
Resolved string `json:"resolved"`
Integrity string `json:"integrity"`
Requires map[string]string
}
type Package struct {
Version string `json:"version"`
Resolved string `json:"resolved"`
Integrity string `json:"integrity"`
License string `json:""`
}
// parsePackageLock parses a package-lock.json and returns the discovered JavaScript packages.
@@ -46,12 +54,28 @@ func parsePackageLock(path string, reader io.Reader) ([]*pkg.Package, []artifact
} else if err != nil {
return nil, nil, fmt.Errorf("failed to parse package-lock.json file: %w", err)
}
licenseMap := make(map[string]string)
for _, pkgMeta := range lock.Packages {
var sb strings.Builder
sb.WriteString(pkgMeta.Resolved)
sb.WriteString(pkgMeta.Integrity)
licenseMap[sb.String()] = pkgMeta.License
}
for name, pkgMeta := range lock.Dependencies {
var sb strings.Builder
sb.WriteString(pkgMeta.Resolved)
sb.WriteString(pkgMeta.Integrity)
var licenses []string
if license, exists := licenseMap[sb.String()]; exists {
licenses = append(licenses, license)
}
packages = append(packages, &pkg.Package{
Name: name,
Version: pkgMeta.Version,
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Licenses: licenses,
})
}
}
@@ -30,6 +30,12 @@ func assertPkgsEqual(t *testing.T, actual []*pkg.Package, expected map[string]pk
func TestParsePackageLock(t *testing.T) {
expected := map[string]pkg.Package{
"@actions/core": {
Name: "@actions/core",
Version: "1.6.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
"wordwrap": {
Name: "wordwrap",
Version: "0.0.3",
@@ -105,3 +111,47 @@ func TestParsePackageLock(t *testing.T) {
assertPkgsEqual(t, actual, expected)
}
func TestParsePackageLockV2(t *testing.T) {
expected := map[string]pkg.Package{
"@types/prop-types": {
Name: "@types/prop-types",
Version: "15.7.5",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Licenses: []string{"MIT"},
},
"@types/react": {
Name: "@types/prop-types",
Version: "18.0.17",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Licenses: []string{"MIT"},
},
"@types/scheduler": {
Name: "@types/scheduler",
Version: "0.16.2",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Licenses: []string{"MIT"},
},
"csstype": {
Name: "csstype",
Version: "3.1.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Licenses: []string{"MIT"},
},
}
fixture, err := os.Open("test-fixtures/pkg-lock/package-lock-2.json")
if err != nil {
t.Fatalf("failed to open fixture: %+v", err)
}
actual, _, err := parsePackageLock(fixture.Name(), fixture)
if err != nil {
t.Fatalf("failed to parse package-lock.json: %+v", err)
}
assertPkgsEqual(t, actual, expected)
}
@@ -0,0 +1,43 @@
package javascript
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 = parsePnpmLock
type pnpmLockYaml struct {
Dependencies map[string]string `json:"dependencies"`
}
func parsePnpmLock(path 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 pnpm-lock.yaml file: %w", err)
}
var pkgs []*pkg.Package
var lockFile pnpmLockYaml
if err := yaml.Unmarshal(bytes, &lockFile); err != nil {
return nil, nil, fmt.Errorf("failed to parse pnpm-lock.yaml file: %w", err)
}
for name, version := range lockFile.Dependencies {
pkgs = append(pkgs, &pkg.Package{
Name: name,
Version: version,
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
})
}
return pkgs, nil, nil
}
@@ -0,0 +1,58 @@
package javascript
import (
"os"
"sort"
"testing"
"github.com/anchore/syft/syft/pkg"
"github.com/go-test/deep"
)
func fixtureP(str string) *string {
return &str
}
func TestParsePnpmLock(t *testing.T) {
expected := []*pkg.Package{
{
Name: "nanoid",
Version: "3.3.4",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
{
Name: "picocolors",
Version: "1.0.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
{
Name: "source-map-js",
Version: "1.0.2",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
}
fixture, err := os.Open("test-fixtures/pnpm/pnpm-lock.yaml")
if err != nil {
t.Fatalf("failed to open fixture: %+v", err)
}
// TODO: no relationships are under test yet
actual, _, err := parsePnpmLock(fixture.Name(), fixture)
if err != nil {
t.Error(err)
}
// we have to sort this for expected to match actual since yaml maps are unordered
sort.Slice(actual, func(p, q int) bool {
return actual[p].Name < actual[q].Name
})
differences := deep.Equal(expected, actual)
if differences != nil {
t.Errorf("returned package list differed from expectation: %+v", differences)
}
}
@@ -0,0 +1,315 @@
{
"version": "6.14.6",
"name": "npm",
"private": true,
"description": "a package manager for JavaScript",
"keywords": [
"install",
"modules",
"package manager",
"package.json"
],
"preferGlobal": true,
"config": {
"publishtest": false
},
"homepage": "https://docs.npmjs.com/",
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
"repository": {
"type": "git",
"url": "https://github.com/npm/cli"
},
"bugs": {
"url": "https://npm.community/c/bugs"
},
"directories": {
"bin": "./bin",
"doc": "./doc",
"lib": "./lib",
"man": "./man"
},
"main": "./lib/npm.js",
"bin": {
"npm": "./bin/npm-cli.js",
"npx": "./bin/npx-cli.js"
},
"dependencies": {
"JSONStream": "^1.3.5",
"abbrev": "~1.1.1",
"ansicolors": "~0.3.2",
"ansistyles": "~0.1.3",
"aproba": "^2.0.0",
"archy": "~1.0.0",
"bin-links": "^1.1.7",
"bluebird": "^3.5.5",
"byte-size": "^5.0.1",
"cacache": "^12.0.3",
"call-limit": "^1.1.1",
"chownr": "^1.1.4",
"ci-info": "^2.0.0",
"cli-columns": "^3.1.2",
"cli-table3": "^0.5.1",
"cmd-shim": "^3.0.3",
"columnify": "~1.5.4",
"config-chain": "^1.1.12",
"detect-indent": "~5.0.0",
"detect-newline": "^2.1.0",
"dezalgo": "~1.0.3",
"editor": "~1.0.0",
"figgy-pudding": "^3.5.1",
"find-npm-prefix": "^1.0.2",
"fs-vacuum": "~1.2.10",
"fs-write-stream-atomic": "~1.0.10",
"gentle-fs": "^2.3.0",
"glob": "^7.1.6",
"graceful-fs": "^4.2.4",
"has-unicode": "~2.0.1",
"hosted-git-info": "^2.8.8",
"iferr": "^1.0.2",
"infer-owner": "^1.0.4",
"inflight": "~1.0.6",
"inherits": "^2.0.4",
"ini": "^1.3.5",
"init-package-json": "^1.10.3",
"is-cidr": "^3.0.0",
"json-parse-better-errors": "^1.0.2",
"lazy-property": "~1.0.0",
"libcipm": "^4.0.7",
"libnpm": "^3.0.1",
"libnpmaccess": "^3.0.2",
"libnpmhook": "^5.0.3",
"libnpmorg": "^1.0.1",
"libnpmsearch": "^2.0.2",
"libnpmteam": "^1.0.2",
"libnpx": "^10.2.2",
"lock-verify": "^2.1.0",
"lockfile": "^1.0.4",
"lodash._baseuniq": "~4.6.0",
"lodash.clonedeep": "~4.5.0",
"lodash.union": "~4.6.0",
"lodash.uniq": "~4.5.0",
"lodash.without": "~4.4.0",
"lru-cache": "^5.1.1",
"meant": "~1.0.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.5",
"move-concurrently": "^1.0.1",
"node-gyp": "^5.1.0",
"nopt": "^4.0.3",
"normalize-package-data": "^2.5.0",
"npm-audit-report": "^1.3.2",
"npm-cache-filename": "~1.0.2",
"npm-install-checks": "^3.0.2",
"npm-lifecycle": "^3.1.4",
"npm-package-arg": "^6.1.1",
"npm-packlist": "^1.4.8",
"npm-pick-manifest": "^3.0.2",
"npm-profile": "^4.0.4",
"npm-registry-fetch": "^4.0.5",
"npm-user-validate": "~1.0.0",
"npmlog": "~4.1.2",
"once": "~1.4.0",
"opener": "^1.5.1",
"osenv": "^0.1.5",
"pacote": "^9.5.12",
"path-is-inside": "~1.0.2",
"promise-inflight": "~1.0.1",
"qrcode-terminal": "^0.12.0",
"query-string": "^6.8.2",
"qw": "~1.0.1",
"read": "~1.0.7",
"read-cmd-shim": "^1.0.5",
"read-installed": "~4.0.3",
"read-package-json": "^2.1.1",
"read-package-tree": "^5.3.1",
"readable-stream": "^3.6.0",
"readdir-scoped-modules": "^1.1.0",
"request": "^2.88.0",
"retry": "^0.12.0",
"rimraf": "^2.7.1",
"safe-buffer": "^5.1.2",
"semver": "^5.7.1",
"sha": "^3.0.0",
"slide": "~1.1.6",
"sorted-object": "~2.0.1",
"sorted-union-stream": "~2.1.3",
"ssri": "^6.0.1",
"stringify-package": "^1.0.1",
"tar": "^4.4.13",
"text-table": "~0.2.0",
"tiny-relative-date": "^1.3.0",
"uid-number": "0.0.6",
"umask": "~1.1.0",
"unique-filename": "^1.1.1",
"unpipe": "~1.0.0",
"update-notifier": "^2.5.0",
"uuid": "^3.3.3",
"validate-npm-package-license": "^3.0.4",
"validate-npm-package-name": "~3.0.0",
"which": "^1.3.1",
"worker-farm": "^1.7.0",
"write-file-atomic": "^2.4.3"
},
"bundleDependencies": [
"abbrev",
"ansicolors",
"ansistyles",
"aproba",
"archy",
"bin-links",
"bluebird",
"byte-size",
"cacache",
"call-limit",
"chownr",
"ci-info",
"cli-columns",
"cli-table3",
"cmd-shim",
"columnify",
"config-chain",
"debuglog",
"detect-indent",
"detect-newline",
"dezalgo",
"editor",
"figgy-pudding",
"find-npm-prefix",
"fs-vacuum",
"fs-write-stream-atomic",
"gentle-fs",
"glob",
"graceful-fs",
"has-unicode",
"hosted-git-info",
"iferr",
"imurmurhash",
"infer-owner",
"inflight",
"inherits",
"ini",
"init-package-json",
"is-cidr",
"json-parse-better-errors",
"JSONStream",
"lazy-property",
"libcipm",
"libnpm",
"libnpmaccess",
"libnpmhook",
"libnpmorg",
"libnpmsearch",
"libnpmteam",
"libnpx",
"lock-verify",
"lockfile",
"lodash._baseindexof",
"lodash._baseuniq",
"lodash._bindcallback",
"lodash._cacheindexof",
"lodash._createcache",
"lodash._getnative",
"lodash.clonedeep",
"lodash.restparam",
"lodash.union",
"lodash.uniq",
"lodash.without",
"lru-cache",
"meant",
"mississippi",
"mkdirp",
"move-concurrently",
"node-gyp",
"nopt",
"normalize-package-data",
"npm-audit-report",
"npm-cache-filename",
"npm-install-checks",
"npm-lifecycle",
"npm-package-arg",
"npm-packlist",
"npm-pick-manifest",
"npm-profile",
"npm-registry-fetch",
"npm-user-validate",
"npmlog",
"once",
"opener",
"osenv",
"pacote",
"path-is-inside",
"promise-inflight",
"qrcode-terminal",
"query-string",
"qw",
"read-cmd-shim",
"read-installed",
"read-package-json",
"read-package-tree",
"read",
"readable-stream",
"readdir-scoped-modules",
"request",
"retry",
"rimraf",
"safe-buffer",
"semver",
"sha",
"slide",
"sorted-object",
"sorted-union-stream",
"ssri",
"stringify-package",
"tar",
"text-table",
"tiny-relative-date",
"uid-number",
"umask",
"unique-filename",
"unpipe",
"update-notifier",
"uuid",
"validate-npm-package-license",
"validate-npm-package-name",
"which",
"worker-farm",
"write-file-atomic"
],
"devDependencies": {
"deep-equal": "^1.0.1",
"get-stream": "^4.1.0",
"licensee": "^7.0.3",
"marked": "^0.6.3",
"marked-man": "^0.6.0",
"npm-registry-couchapp": "^2.7.4",
"npm-registry-mock": "^1.3.1",
"require-inject": "^1.4.4",
"sprintf-js": "^1.1.2",
"standard": "^11.0.1",
"tacks": "^1.3.0",
"tap": "^12.7.0",
"tar-stream": "^2.1.0"
},
"scripts": {
"dumpconf": "env | grep npm | sort | uniq",
"prepare": "node bin/npm-cli.js rebuild && node bin/npm-cli.js --no-audit --no-timing prune --prefix=. --no-global && rimraf test/*/*/node_modules && make -j4 mandocs",
"preversion": "bash scripts/update-authors.sh && git add AUTHORS && git commit -m \"update AUTHORS\" || true",
"licenses": "licensee --production --errors-only",
"tap": "tap -J --timeout 300 --no-esm",
"tap-cover": "tap -J --nyc-arg=--cache --coverage --timeout 600 --no-esm",
"lint": "standard",
"pretest": "npm run lint",
"test": "npm run test-tap --",
"test:nocleanup": "NO_TEST_CLEANUP=1 npm run test --",
"sudotest": "sudo npm run tap -- \"test/tap/*.js\"",
"sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 npm run tap -- \"test/tap/*.js\"",
"posttest": "rimraf test/npm_cache*",
"test-coverage": "npm run tap-cover -- \"test/tap/*.js\" \"test/network/*.js\"",
"test-tap": "npm run tap -- \"test/tap/*.js\" \"test/network/*.js\"",
"test-node": "tap --timeout 240 \"test/tap/*.js\" \"test/network/*.js\""
},
"license": "Artistic-2.0",
"engines": {
"node": "6 >=6.2.0 || 8 || >=9.3.0"
}
}
@@ -0,0 +1,44 @@
{
"name": "@actions/core",
"version": "1.6.0",
"description": "Actions core lib",
"keywords": [
"github",
"actions",
"core"
],
"homepage": "https://github.com/actions/toolkit/tree/main/packages/core",
"license": "MIT",
"main": "lib/core.js",
"types": "lib/core.d.ts",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib",
"!.DS_Store"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/actions/toolkit.git",
"directory": "packages/core"
},
"scripts": {
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
"test": "echo \"Error: run tests from root\" && exit 1",
"tsc": "tsc"
},
"bugs": {
"url": "https://github.com/actions/toolkit/issues"
},
"dependencies": {
"@actions/http-client": "^1.0.11"
},
"devDependencies": {
"@types/node": "^12.0.2"
}
}
@@ -0,0 +1,59 @@
{
"name": "cowsay",
"version": "1.4.0",
"description": "cowsay is a configurable talking cow",
"keywords": [
"cow",
"cowsay",
"cowthink",
"figlet",
"talking",
"ASCII"
],
"homepage": "https://github.com/piuccio/cowsay",
"author": {
"name": "Fabio Crisci",
"email": "piuccio@gmail.com",
"url": "https://github.com/piuccio/"
},
"license": "MIT",
"main": "./index",
"module": "./build/cowsay.es.js",
"browser": "./build/cowsay.umd.js",
"bin": {
"cowsay": "./cli.js",
"cowthink": "./cli.js"
},
"files": [
"index.js",
"cli.js",
"build/",
"cows/",
"lib/"
],
"repository": {
"type": "git",
"url": "https://github.com/piuccio/cowsay.git"
},
"scripts": {
"prepublish": "rollup -c",
"test": "node test.js"
},
"dependencies": {
"get-stdin": "^5.0.1",
"optimist": "~0.6.1",
"string-width": "~2.1.1",
"strip-eof": "^1.0.0"
},
"devDependencies": {
"nodeunit": "~0.11.1",
"rollup": "^0.48.2",
"rollup-plugin-commonjs": "^8.2.0",
"rollup-plugin-node-resolve": "^3.0.0",
"rollup-plugin-string": "^2.0.2"
},
"preferGlobal": true,
"engines": {
"node": ">= 4"
}
}
@@ -0,0 +1,71 @@
{
"name": "npm",
"version": "6.14.6",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "npm",
"version": "6.14.6",
"dependencies": {
"@types/react": "^18.0.9"
}
},
"node_modules/@types/prop-types": {
"version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha1-XxnSuFqY6VWANvajysyIGUIPBc8=",
"license": "MIT"
},
"node_modules/@types/react": {
"version": "18.0.17",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.17.tgz",
"integrity": "sha1-RYPZwyLWfv5LOak10iPtzHBQzPQ=",
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha1-GmL4lSVyPd4kuhsBsJK/XfitTTk=",
"license": "MIT"
},
"node_modules/csstype": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha1-TdysNxjXh8+d8NG30VAzklyPKfI=",
"license": "MIT"
}
},
"dependencies": {
"@types/prop-types": {
"version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha1-XxnSuFqY6VWANvajysyIGUIPBc8="
},
"@types/react": {
"version": "18.0.17",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.17.tgz",
"integrity": "sha1-RYPZwyLWfv5LOak10iPtzHBQzPQ=",
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha1-GmL4lSVyPd4kuhsBsJK/XfitTTk="
},
"csstype": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha1-TdysNxjXh8+d8NG30VAzklyPKfI="
}
}
}
@@ -2,6 +2,14 @@
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@actions/core": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz",
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==",
"requires": {
"@actions/http-client": "^1.0.11"
}
},
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
@@ -0,0 +1,72 @@
lockfileVersion: 5.4
specifiers:
'@logux/eslint-config': ^47.2.0
'@size-limit/preset-small-lib': ^8.0.0
'@types/fs-extra': ^9.0.13
'@types/node': ^18.6.4
'@typescript-eslint/eslint-plugin': ^5.32.0
'@typescript-eslint/parser': ^5.32.0
c8: ^7.12.0
check-dts: ^0.6.7
clean-publish: ^4.0.1
concat-with-sourcemaps: ^1.1.0
eslint: ^8.21.0
eslint-config-standard: ^17.0.0
eslint-plugin-import: ^2.26.0
eslint-plugin-n: ^15.2.4
eslint-plugin-prefer-let: ^3.0.1
eslint-plugin-promise: ^6.0.0
fs-extra: ^10.1.0
nanodelay: ^1.0.8
nanoid: ^3.3.4
nanospy: ^0.5.0
picocolors: ^1.0.0
postcss-parser-tests: ^8.5.1
simple-git-hooks: ^2.8.0
size-limit: ^8.0.0
source-map-js: ^1.0.2
strip-ansi: ^6.0.1
ts-node: ^10.9.1
typescript: ^4.7.4
uvu: ^0.5.6
dependencies:
nanoid: 3.3.4
picocolors: 1.0.0
source-map-js: 1.0.2
devDependencies:
'@logux/eslint-config': 47.2.0_7hz3xvmviof7onfgk6hpedqcom
'@size-limit/preset-small-lib': 8.0.0_size-limit@8.0.0
'@types/fs-extra': 9.0.13
'@types/node': 18.6.4
'@typescript-eslint/eslint-plugin': 5.32.0_iosr3hrei2tubxveewluhu5lhy
'@typescript-eslint/parser': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
c8: 7.12.0
check-dts: 0.6.7_typescript@4.7.4
clean-publish: 4.0.1
concat-with-sourcemaps: 1.1.0
eslint: 8.21.0
eslint-config-standard: 17.0.0_dfwa53o44x4e5xhsfv5mvfhk5a
eslint-plugin-import: 2.26.0_wuikv5nqgdfyng42xxm7lklfmi
eslint-plugin-n: 15.2.4_eslint@8.21.0
eslint-plugin-prefer-let: 3.0.1
eslint-plugin-promise: 6.0.0_eslint@8.21.0
fs-extra: 10.1.0
nanodelay: 1.0.8
nanospy: 0.5.0
postcss-parser-tests: 8.5.1
simple-git-hooks: 2.8.0
size-limit: 8.0.0
strip-ansi: 6.0.1
ts-node: 10.9.1_hn66opzbaneygq52jmwjxha6su
typescript: 4.7.4
uvu: 0.5.6
packages:
/@bcoe/v8-coverage/0.2.3:
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
dev: true
# removed other packages
+5
View File
@@ -37,6 +37,11 @@ func (c *Cataloger) Name() string {
return "portage-cataloger"
}
// UsesExternalSources indicates that the portage cataloger does not use external sources
func (c *Cataloger) UsesExternalSources() bool {
return false
}
// 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)
@@ -33,6 +33,11 @@ func (c *PackageCataloger) Name() string {
return "python-package-cataloger"
}
// UsesExternalSources indicates that the python package cataloger does not use external sources
func (c *PackageCataloger) UsesExternalSources() bool {
return false
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing python egg and wheel installations.
func (c *PackageCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
var fileMatches []source.Location
+4 -3
View File
@@ -15,9 +15,10 @@ import (
var _ common.ParserFn = parseSetup
// match examples:
// 'pathlib3==2.2.0;python_version<"3.6"' --> match(name=pathlib3 version=2.2.0)
// "mypy==v0.770", --> match(name=mypy version=v0.770)
// " mypy2 == v0.770", ' mypy3== v0.770', --> match(name=mypy2 version=v0.770), match(name=mypy3, version=v0.770)
//
// 'pathlib3==2.2.0;python_version<"3.6"' --> match(name=pathlib3 version=2.2.0)
// "mypy==v0.770", --> match(name=mypy version=v0.770)
// " mypy2 == v0.770", ' mypy3== v0.770', --> match(name=mypy2 version=v0.770), match(name=mypy3, version=v0.770)
var pinnedDependency = regexp.MustCompile(`['"]\W?(\w+\W?==\W?[\w\.]*)`)
func parseSetup(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
+5
View File
@@ -27,6 +27,11 @@ func (c *Cataloger) Name() string {
return catalogerName
}
// UsesExternalSources indicates that the rpmdb cataloger does not use external sources
func (c *Cataloger) UsesExternalSources() bool {
return false
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation.
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
fileMatches, err := resolver.FilesByGlob(pkg.RpmDBGlob)
+11 -10
View File
@@ -69,16 +69,17 @@ func newPkg(resolver source.FilePathResolver, dbLocation source.Location, entry
}
metadata := pkg.RpmdbMetadata{
Name: entry.Name,
Version: entry.Version,
Epoch: entry.Epoch,
Arch: entry.Arch,
Release: entry.Release,
SourceRpm: entry.SourceRpm,
Vendor: entry.Vendor,
License: entry.License,
Size: entry.Size,
Files: fileRecords,
Name: entry.Name,
Version: entry.Version,
Epoch: entry.Epoch,
Arch: entry.Arch,
Release: entry.Release,
SourceRpm: entry.SourceRpm,
Vendor: entry.Vendor,
License: entry.License,
Size: entry.Size,
ModularityLabel: entry.Modularitylabel,
Files: fileRecords,
}
p := pkg.Package{
@@ -12,7 +12,7 @@ import (
rustaudit "github.com/microsoft/go-rustaudit"
)
const catalogerName = "rust-audit-binary-cataloger"
const catalogerName = "cargo-auditable-binary-cataloger"
type Cataloger struct{}
@@ -27,6 +27,11 @@ func (c *Cataloger) Name() string {
return catalogerName
}
// UsesExternalSources indicates that the audit binary cataloger does not use external sources
func (c *Cataloger) UsesExternalSources() bool {
return false
}
// 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
+1 -1
View File
@@ -13,5 +13,5 @@ func NewCargoLockCataloger() *common.GenericCataloger {
"**/Cargo.lock": parseCargoLock,
}
return common.NewGenericCataloger(nil, globParsers, "rust-cataloger")
return common.NewGenericCataloger(nil, globParsers, "rust-cargo-lock-cataloger")
}
+1
View File
@@ -19,6 +19,7 @@ type NpmPackageJSONMetadata struct {
Homepage string `mapstructure:"homepage" json:"homepage"`
Description string `mapstructure:"description" json:"description"`
URL string `mapstructure:"url" json:"url"`
Private bool `mapstructure:"private" json:"private"`
}
// PackageURL returns the PURL for the specific NPM package (see https://github.com/package-url/purl-spec)
+11 -10
View File
@@ -26,16 +26,17 @@ var (
// RpmdbMetadata represents all captured data for a RPM DB package entry.
type RpmdbMetadata struct {
Name string `json:"name"`
Version string `json:"version"`
Epoch *int `json:"epoch" cyclonedx:"epoch" jsonschema:"nullable"`
Arch string `json:"architecture"`
Release string `json:"release" cyclonedx:"release"`
SourceRpm string `json:"sourceRpm" cyclonedx:"sourceRpm"`
Size int `json:"size" cyclonedx:"size"`
License string `json:"license"`
Vendor string `json:"vendor"`
Files []RpmdbFileRecord `json:"files"`
Name string `json:"name"`
Version string `json:"version"`
Epoch *int `json:"epoch" cyclonedx:"epoch" jsonschema:"nullable"`
Arch string `json:"architecture"`
Release string `json:"release" cyclonedx:"release"`
SourceRpm string `json:"sourceRpm" cyclonedx:"sourceRpm"`
Size int `json:"size" cyclonedx:"size"`
License string `json:"license"`
Vendor string `json:"vendor"`
ModularityLabel string `json:"modularityLabel"`
Files []RpmdbFileRecord `json:"files"`
}
// RpmdbFileRecord represents the file metadata for a single file attributed to a RPM package.
+1 -2
View File
@@ -8,7 +8,6 @@ package source
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
@@ -345,7 +344,7 @@ func (s *Source) FileResolver(scope Scope) (FileResolver, error) {
}
func unarchiveToTmp(path string, unarchiver archiver.Unarchiver) (string, func(), error) {
tempDir, err := ioutil.TempDir("", "syft-archive-contents-")
tempDir, err := os.MkdirTemp("", "syft-archive-contents-")
if err != nil {
return "", func() {}, fmt.Errorf("unable to create tempdir for archive processing: %w", err)
}
+78
View File
@@ -0,0 +1,78 @@
package cli
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
type conversion struct {
To string
From string
}
func TestConvertCmdFlags(t *testing.T) {
commonAssertions := []traitAssertion{
func(tb testing.TB, stdout, _ string, _ int) {
tb.Helper()
if len(stdout) < 1000 {
tb.Errorf("there may not be any report output (len=%d)", len(stdout))
}
},
assertSuccessfulReturnCode,
}
tests := []struct {
name string
conversions []conversion
env map[string]string
assertions []traitAssertion
}{
{
name: "syft-format convertable to spdx-json",
conversions: []conversion{
{To: "syft-json", From: "spdx-json"},
{To: "syft-json", From: "cyclonedx-json"},
{To: "spdx-json", From: "syft-json"},
{To: "spdx-json", From: "cyclonedx-json"},
{To: "cyclonedx-json", From: "syft-json"},
{To: "cyclonedx-json", From: "spdx-json"},
},
assertions: commonAssertions,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
for _, c := range test.conversions {
sbomArgs := []string{"dir:./test-fixtures/image-pkg-coverage", "-o", c.From}
cmd, stdout, stderr := runSyft(t, test.env, sbomArgs...)
if cmd.ProcessState.ExitCode() != 0 {
t.Fatalf("failure executing syft creating an sbom")
t.Log("STDOUT:\n", stdout)
t.Log("STDERR:\n", stderr)
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
return
}
tempDir := t.TempDir()
sbomFile := filepath.Join(tempDir, "sbom.json")
require.NoError(t, os.WriteFile(sbomFile, []byte(stdout), 0666))
convertArgs := []string{"convert", sbomFile, "-o", c.To}
cmd, stdout, stderr = runSyft(t, test.env, convertArgs...)
for _, traitFn := range test.assertions {
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
}
if t.Failed() {
t.Log("STDOUT:\n", stdout)
t.Log("STDERR:\n", stderr)
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
}
}
})
}
}
+2 -1
View File
@@ -229,9 +229,10 @@ func TestPackagesCmdFlags(t *testing.T) {
},
{
name: "catalogers-option",
// This will detect enable python-index-cataloger, python-package-cataloger and ruby-gemspec cataloger
args: []string{"packages", "-o", "json", "--catalogers", "python,ruby-gemspec", coverageImage},
assertions: []traitAssertion{
assertPackageCount(6),
assertPackageCount(13),
assertSuccessfulReturnCode,
},
},
+23 -1
View File
@@ -3,6 +3,7 @@ package integration
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/linux"
@@ -54,7 +55,7 @@ func BenchmarkImagePackageCatalogers(b *testing.B) {
}
func TestPkgCoverageImage(t *testing.T) {
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope, false)
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope, nil)
observedLanguages := internal.NewStringSet()
definedLanguages := internal.NewStringSet()
@@ -221,3 +222,24 @@ func TestPkgCoverageDirectory(t *testing.T) {
t.Errorf("package coverage incomplete (packages=%d, coverage=%d)", len(definedPkgs), len(observedPkgs))
}
}
func TestPkgCoverageCatalogerConfiguration(t *testing.T) {
// Check that cataloger configuration can be used to run a cataloger on a source
// for which that cataloger isn't enabled by defauly
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope, []string{"rust"})
observedLanguages := internal.NewStringSet()
definedLanguages := internal.NewStringSet()
definedLanguages.Add("rust")
for actualPkg := range sbom.Artifacts.PackageCatalog.Enumerate() {
observedLanguages.Add(actualPkg.Language.String())
}
assert.Equal(t, definedLanguages, observedLanguages)
// Verify that rust isn't actually an image cataloger
c := cataloger.DefaultConfig()
c.Catalogers = []string{"rust"}
assert.Len(t, cataloger.ImageCatalogers(c), 0)
}
+1 -1
View File
@@ -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, false)
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope, nil)
format := syft.FormatByID(syftjson.ID)
f, err := ioutil.TempFile("", "test-convert-sbom-")
+3 -2
View File
@@ -1,16 +1,17 @@
package integration
import (
"github.com/anchore/syft/syft/source"
"testing"
"github.com/anchore/syft/syft/source"
"github.com/stretchr/testify/assert"
"github.com/anchore/syft/syft/linux"
)
func TestDistroImage(t *testing.T) {
sbom, _ := catalogFixtureImage(t, "image-distro-id", source.SquashedScope, false)
sbom, _ := catalogFixtureImage(t, "image-distro-id", source.SquashedScope, nil)
expected := &linux.Release{
PrettyName: "BusyBox v1.31.1",
+4 -3
View File
@@ -3,13 +3,14 @@ package integration
import (
"bytes"
"fmt"
"regexp"
"testing"
"github.com/anchore/syft/internal/formats/cyclonedxjson"
"github.com/anchore/syft/internal/formats/cyclonedxxml"
"github.com/anchore/syft/internal/formats/syftjson"
"github.com/anchore/syft/syft/source"
"github.com/google/go-cmp/cmp"
"regexp"
"testing"
"github.com/anchore/syft/syft/sbom"
"github.com/stretchr/testify/require"
@@ -64,7 +65,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, false)
originalSBOM, _ := catalogFixtureImage(t, image, source.SquashedScope, nil)
format := syft.FormatByID(test.formatOption)
require.NotNil(t, format)
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func TestMarinerDistroless(t *testing.T) {
sbom, _ := catalogFixtureImage(t, "image-mariner-distroless", source.SquashedScope, false)
sbom, _ := catalogFixtureImage(t, "image-mariner-distroless", source.SquashedScope, nil)
expectedPkgs := 12
actualPkgs := 0
@@ -1,11 +1,14 @@
//go:build !arm64
package integration
import (
"fmt"
"testing"
"github.com/anchore/syft/syft/source"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)
func TestPackageDeduplication(t *testing.T) {
@@ -56,7 +59,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, false)
sbom, _ := catalogFixtureImage(t, "image-vertical-package-dups", tt.scope, nil)
assert.Equal(t, tt.packageCount, sbom.Artifacts.PackageCatalog.PackageCount())
for name, expectedInstanceCount := range tt.instanceCount {
@@ -3,9 +3,10 @@ package integration
import (
"bytes"
"encoding/json"
"github.com/anchore/syft/syft/source"
"testing"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/internal/formats/syftjson"
syftjsonModel "github.com/anchore/syft/internal/formats/syftjson/model"
)
@@ -23,7 +24,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, false)
sbom, _ := catalogFixtureImage(t, test.fixture, source.SquashedScope, nil)
output := bytes.NewBufferString("")
err := syftjson.Format().Encode(output, sbom)
@@ -1,16 +1,17 @@
package integration
import (
"github.com/anchore/syft/syft/source"
"testing"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/pkg"
)
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, false)
sbom, _ := catalogFixtureImage(t, "image-large-apk-data", source.SquashedScope, nil)
expectedPkgs := 58
actualPkgs := 0
@@ -1,10 +1,11 @@
package integration
import (
"github.com/anchore/syft/syft/source"
"strings"
"testing"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/pkg"
)
@@ -16,7 +17,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, false)
sbom, _ := catalogFixtureImage(t, "image-go-bin-arch-coverage", source.SquashedScope, nil)
var actualELF, actualWIN, actualMACOS int
@@ -1,10 +1,11 @@
package integration
import (
"github.com/anchore/syft/syft/source"
"testing"
"github.com/anchore/syft/syft/source"
)
func TestRegressionJavaNoMainPackage(t *testing.T) { // Regression: https://github.com/anchore/syft/issues/252
catalogFixtureImage(t, "image-java-no-main-package", source.SquashedScope, false)
catalogFixtureImage(t, "image-java-no-main-package", source.SquashedScope, nil)
}
+1 -1
View File
@@ -8,7 +8,7 @@ import (
)
func TestRustAudit(t *testing.T) {
sbom, _ := catalogFixtureImage(t, "image-rust-auditable", source.SquashedScope, true)
sbom, _ := catalogFixtureImage(t, "image-rust-auditable", source.SquashedScope, []string{"all"})
expectedPkgs := 2
actualPkgs := 0
+1 -1
View File
@@ -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, false)
sbom, _ := catalogFixtureImage(t, "image-sqlite-rpmdb", source.SquashedScope, nil)
expectedPkgs := 139
actualPkgs := 0
@@ -1,4 +1,4 @@
FROM jenkins:2.60.3
FROM jenkins/jenkins:2.346.3-slim-jdk17
USER root

Some files were not shown because too many files have changed in this diff Show More