Compare commits

...
240 Commits
Author SHA1 Message Date
Keith Zantow 7845381331 chore: update tools-golang to v0.5.0 (#1717)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-04-05 13:59:52 -04:00
7464079a09 Add Nix cataloger (#1696)
* Add Basic Nix Cataloger

Signed-off-by: Julio Tain Sueiras <juliosueiras@gmail.com>

* Update nix def for the latest syft definition

Signed-off-by: Julio Tain Sueiras <juliosueiras@gmail.com>

* capture nix package files on pkg.NixStoreMetadata

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

* fix unit tests and linting

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

* update JSON schema

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

* address review comments

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

* Update syft/pkg/cataloger/nix/parse_nix_store_path_test.go

Co-authored-by: Florian Klink <flokli@flokli.de>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* support unstable version conventions

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

* update json schema relative to main branch

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

* update syft json with v7.1.1 schema

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

* fix CLI tests

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

* remove extra continue statement

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

* add Nix to list of supported ecosystems

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

---------

Signed-off-by: Julio Tain Sueiras <juliosueiras@gmail.com>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Julio Tain Sueiras <juliosueiras@gmail.com>
Co-authored-by: Florian Klink <flokli@flokli.de>
2023-04-04 10:53:56 -04:00
Alex Goodman 8a574c9ed9 refactor spdx tooling test to reduce intermittent failures (#1707)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-04-03 18:43:28 +00:00
Alex Goodman 681d250fdc Capture file ownership relationships from portage ecosystem (#1702)
* add portage as file owners

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

* fix tests

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

* fix linting

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

* update json schema with NPM files

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

---------

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-04-03 09:46:18 -04:00
Keith Zantow 2022ffa0e5 chore: update deprecated set-output calls (#1705)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-04-03 09:36:11 -04:00
Christopher Angelo Phillips dfcc07e512 feat: Add config option to allow user to select the default image source location
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-03-31 10:04:10 -04:00
dependabot[bot] 2fa238af7c chore(deps): bump github.com/docker/docker (#1699)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 23.0.1+incompatible to 23.0.2+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v23.0.1...v23.0.2)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-29 10:00:37 -04:00
anchore-actions-token-generator[bot]andspiffcs 63bbd1e3ed chore(deps): update bootstrap tools to latest versions (#1697)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2023-03-27 09:17:34 -04:00
anchore-actions-token-generator[bot]andwagoodman 81b87dd108 chore(deps): update stereoscope to d7551b7f46f53179922d6229709d3d1602881080 (#1693)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: wagoodman <wagoodman@users.noreply.github.com>
2023-03-23 16:30:08 +00:00
Christopher Angelo Phillips f473bb75a8 1577 spdxlicense generate (#1691)
Update the license_list.go to have more permissible inputs for greater SPDXID matching.
EX:
GPL3 gpl3 gpl-3 and GPL-3 can all map to GPL-3.0-only

By moving all strings to lower and removing the "-" we're able to return valid SPDX license ID for a greater diversity of input strings.
---------

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-03-23 11:48:24 -04:00
dependabot[bot] 539bc2afcb chore(deps): bump github.com/vbatts/go-mtree from 0.5.2 to 0.5.3 (#1692)
Bumps [github.com/vbatts/go-mtree](https://github.com/vbatts/go-mtree) from 0.5.2 to 0.5.3.
- [Release notes](https://github.com/vbatts/go-mtree/releases)
- [Changelog](https://github.com/vbatts/go-mtree/blob/main/releases.md)
- [Commits](https://github.com/vbatts/go-mtree/compare/v0.5.2...v0.5.3)

---
updated-dependencies:
- dependency-name: github.com/vbatts/go-mtree
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 11:09:32 -04:00
Avi DeitcherandKeith Zantow 9fd532246a feat: scan local go mod cache for licenses of golang packages (#1645)
Signed-off-by: Avi Deitcher <avi@deitcher.net>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2023-03-23 10:38:15 -04:00
Keith Zantow 11e926ab2f chore: fix flaky license sorting (#1690)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-03-22 14:41:49 -04:00
dependabot[bot] 168c5aed51 chore(deps): bump github.com/gookit/color from 1.5.2 to 1.5.3 (#1689) 2023-03-22 14:26:58 -04:00
Dan d02c56aa5f fix: shell completion by adding missing usage message required by spf13/cobra (#1688)
Signed-off-by: DanHam <DanHam@users.noreply.github.com>
2023-03-22 13:45:09 -04:00
anchore-actions-token-generator[bot] 829a71cd92 chore(deps): update bootstrap tools to latest versions (#1686) 2023-03-22 09:01:24 -04:00
Keith Zantow 34ace36a9e chore: tweak some workflow text (#1685)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-03-21 11:08:49 -04:00
Alex Goodman 100cf1003d Remove more side effects from application config testing (#1684)
* remove a few side effects from config testing

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

* fix xdg config app name prefix

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

* account for restoring and protecting xdg state throughout testing

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

---------

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-03-20 20:53:45 +00:00
Aidan DelaneyandChristopher Phillips f11a7b5e9f Deprecate config.yaml as valid config source; Add unit regression for correct config paths (#1640)
Warn user of future deprecation of ./config.yaml for v1.0.0 release

---------

Signed-off-by: Aidan Delaney <adelaney21@bloomberg.net>
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-03-20 15:13:35 -04:00
anchore-actions-token-generator[bot] 434aa7fd46 chore: Update syft bootstrap tools to latest versions. (#1682)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-03-20 13:20:48 -04:00
Marc-Etienne Vargenau 5fb0423b72 Update documentation: (#1680)
- Syft is now outputing SPDX 2.3 by default
- Give syntax to get SPDX 2.2

Signed-off-by: Marc-Etienne Vargenau <marc-etienne.vargenau@nokia.com>
2023-03-20 10:10:35 -04:00
anchore-actions-token-generator[bot] 7998520848 chore: Update Stereoscope to 7928713c391e20abaede6a029f4ce37b628a4c8b (#1681) 2023-03-18 10:32:39 -04:00
Keith Zantow d05000ff21 fix: reduce logging for bad dpkg lines (#1675)
* fix: reduce logging for bad dpkg lines to Trace level
---------

Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-03-17 13:08:51 -04:00
witchcraze f66e77e2c6 fix ruby classifier (#1678)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2023-03-17 09:42:20 -04:00
Christopher Angelo Phillips 928c4a55ff feat: add shared dir for easier cleanup (#1676)
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-03-16 16:05:34 -04:00
dependabot[bot] 1899eb50d0 chore(deps): bump github.com/google/go-containerregistry (#1672)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.13.0 to 0.14.0.
- [Release notes](https://github.com/google/go-containerregistry/releases)
- [Changelog](https://github.com/google/go-containerregistry/blob/main/.goreleaser.yml)
- [Commits](https://github.com/google/go-containerregistry/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 12:07:47 -04:00
dependabot[bot] b5ec4d4f08 chore(deps): bump actions/setup-go from 3 to 4 (#1671)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 12:02:07 -04:00
Christopher Angelo Phillips 61362c04fa fix: move defer after error to protect panic case (#1670)
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-03-15 15:29:10 -04:00
Joye Lin e3140063d4 feat: add argocd, helm, kustomize and kubectl binary classifiers (#1663)
* add argocd, helm, kustomize and kubectl binary classifiers
* update golang PURL
* address PR faceback about binary/test-fixtures/Makefile
* remove the /v[n] suffix from the PURL in both argocd and helm

---------

Signed-off-by: y12studio <y12studio@gmail.com>
2023-03-15 14:53:22 -04:00
razzle 1d9ef34ec7 defer closing file (#1668)
Signed-off-by: razzle <harry@razzle.cloud>
2023-03-15 14:50:42 -04:00
Keith Zantow 302735097e fix: remove author contributing to javascript CPEs (#1669) 2023-03-14 14:10:24 +00:00
Keith Zantow cc0a376aba fix: more python matching support (#1667) 2023-03-13 13:26:43 -04:00
anchore-actions-token-generator[bot]andspiffcs b379dd9f27 Update syft bootstrap tools to latest versions. (#1666)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2023-03-13 10:40:13 -04:00
witchcraze a81e0c8008 feat: add ruby classifier (#1665)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2023-03-10 08:29:40 -05:00
anchore-actions-token-generator[bot] 41cbbe09b2 Update syft bootstrap tools to latest versions. (#1658) 2023-03-07 12:54:32 -05:00
Keith Zantow 7714bc0521 fix: improved Python binary detection (#1648) 2023-03-07 10:52:29 -05:00
Weston Steimel 096d2b7bff fix: suppress some known incorrect vendor candidates for npm CPEs (#1659)
Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-03-07 10:18:44 -05:00
Keith Zantow 7cfdffab5f fix: sanitize SPDX LicenseRefs (#1657)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-03-06 10:55:23 -05:00
dependabot[bot] f43953d225 chore(deps): bump golang.org/x/mod from 0.8.0 to 0.9.0 (#1655) 2023-03-06 15:49:34 +00:00
dependabot[bot] eea1b48cbb chore(deps): bump golang.org/x/net from 0.7.0 to 0.8.0 (#1653) 2023-03-06 15:38:34 +00:00
dependabot[bot] a063cf300b chore(deps): bump github.com/spf13/afero from 1.9.4 to 1.9.5 (#1654) 2023-03-06 15:21:35 +00:00
dependabot[bot] b73903519c chore(deps): bump golang.org/x/term from 0.5.0 to 0.6.0 (#1656) 2023-03-06 15:20:43 +00:00
Keith Zantow 304be4a5a1 fix: dotnet PURL types are invalid (#1649)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-03-03 16:45:20 -05:00
Weston Steimel c4cbe211a3 feat: disable cpe vendor wildcards to reduce false positives (#1647)
* improved parsing of vendor from github url

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* stop generating wildcard vendors

Add logic for parsing javascript and ruby package vendor candidates from
url and author fields and stop generating wildcard vendor candidates

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

---------

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-03-03 17:26:46 +00:00
Avi Deitcher 01230aa766 read relative etc/apk/repositories for alpine version when no OS provided (#1615)
Signed-off-by: Avi Deitcher <avi@deitcher.net>
2023-03-02 13:04:56 -05:00
Keith Zantow 5f90d03718 fix: possible race condition (#1639) 2023-03-01 15:35:01 -05:00
Weston Steimel e2ebc9769f fix: remove APK OriginPackage cpe candidates (#1637)
Adding APK OriginPackage CPE candidates to the child package
results in false positives in grype because it can't associate
CPE-based findings to the corresponding OriginPackage APK fixes.

This reverts changing the `upstream` in the PURL for APK packages
as the logic in Grype that uses it expects it to be an APK package
name.  This also allows refactoring to unexport and move the APK
CPE candidate generation logic closer to where CPE generation occurs

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-03-01 17:24:43 +00:00
Keith Zantow 2e6e3b0c74 fix: rebar lock file decoding panic (#1628) 2023-03-01 10:08:29 -05:00
Keith Zantow 24584a4d27 fix: handle individual cataloger panics (#1636) 2023-03-01 10:03:34 -05:00
Weston Steimel 8e1205f7ab fix: apk product/vendor generation for old metadata (#1635)
This fixes some instances where the improved APK CPE generation
logic caused regressions for older alpine package APK metadata.
It now generates multiple "upstream" candidates with both name
and package type which reduces the amount of duplicated code in
the apk cpe gen logic.  This also improves the handling of stream
version packages, so now we can correctly identify packages such
as ruby3.2-rexml as the rexml ruby gem.

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-03-01 14:58:35 +00:00
Weston Steimel e92b0fa629 feat: rust toolchain binary cataloger (#1601)
Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-03-01 14:53:37 +00:00
Weston Steimel bcc0751a40 feat: retain go package info when no module declared (#1632)
Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-03-01 14:26:44 +00:00
Weston Steimel f1169e56fc fix: improved CPE-generation for several more APK packages (#1631)
* fix: correct vendor for musl

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: correct vendor for firefox and thunderbird

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: correct vendor/product for chromium

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: correct product for apache http server

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: correct product for tiff

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: correct vendor for ghostscript

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: correct vendor for openjpeg

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: correct vendor/product for xorg-server

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: correct vendor for podofo

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: correct vendor for wpa_supplicant

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

---------

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-03-01 08:55:40 -05:00
Christopher Angelo Phillips 98e737fc27 chore: update deprecated release flag (#1629)
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-02-27 15:57:56 -05:00
dependabot[bot] ff34594284 chore(deps): bump actions/upload-artifact from 2 to 3 (#1627)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-27 14:17:29 -05:00
Benji Visser 9e953b1da3 feat: add support for SUPPORT_END in /etc/os-release (#1612)
Signed-off-by: Benji Visser <benji@093b.org>
2023-02-27 13:43:19 -05:00
Weston Steimel fbda21f4f4 fix: further improvements to CPE generation for apk packages (#1623)
* fix: consider upstream logic during apk cpe gen
* fix: correct apk CPE for go
* fix: correct apk CPE for ruby
* fix: correct apk CPE for bazel
* fix: correct apk CPE for clang
* fix: correct apk CPE for openjdk
* fix: correct apk CPE for glibc
* fix: correct apk CPE for gli
* fix: correct apk CPE for bas
* fix: correct apk CPE for alsa-lib
* fix: correct apk CPE for alsa
* fix: determine apk cpe vendor from known URLs
* fix: add more url prefix->vendor mappings for apk
* refactor: allow reuse of vendor by url prefix logic
* feat: extract username as vendor candidate from github/gitlab

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-02-27 13:16:04 -05:00
dependabot[bot] d23b4d4cbd chore(deps): bump github.com/stretchr/testify from 1.8.1 to 1.8.2 (#1625)
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.1...v1.8.2)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-27 13:14:20 -05:00
dependabot[bot] f3acff81f3 chore(deps): bump actions/checkout from 2 to 3 (#1626)
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-27 13:14:03 -05:00
Nils Hanke fa0a9fe8f9 feat: set cosign attest predicate type based on Syft output type (#1598)
Signed-off-by: Nils Hanke <nils.hanke@outlook.de>
2023-02-24 15:08:40 -05:00
dependabot[bot] 284bae9d5f chore(deps): bump github.com/spf13/afero from 1.9.3 to 1.9.4 (#1609)
Bumps [github.com/spf13/afero](https://github.com/spf13/afero) from 1.9.3 to 1.9.4.
- [Release notes](https://github.com/spf13/afero/releases)
- [Commits](https://github.com/spf13/afero/compare/v1.9.3...v1.9.4)

---
updated-dependencies:
- dependency-name: github.com/spf13/afero
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-24 15:07:52 -05:00
Weston Steimel 3ee1af0dc6 fix: correct apk purls for other distros (#1620)
The apk purl spec allows for vendor-specific namespace.  I noticed
in the embedded SBOMs from wolfi that the purls are of the form
`pkg:apk/wolfi/curl@7.83.0-r0?arch=x86`, but the current logic in
syft actually prevents purl generation entirely if the distro isn't
alpine, so this corrects that behaviour.

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-02-24 15:07:07 -05:00
Weston Steimel 0c5f03235e refactor: move apk upstream logic to apk metadata (#1619)
* refactor: move apk upstream logic to apk metadata

Export the logic for parsing upstream APK package names
so it can be accessed from apk metadata objects directly.

This also tightens the upstream regex pattern as several
edge cases were being missed.

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: ensure correct handling for apk packages beginning with digits

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: upstream generation for ruby

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

---------

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-02-24 15:59:19 +00:00
Keith Zantow 5e8aa4da5e fix: decoding null apk metadata pullDependencies (#1614)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-02-23 19:55:49 +00:00
Benji Visser abfec62219 feat: haproxy binary matcher (#1591)
Signed-off-by: Benji Visser <benji@093b.org>
2023-02-23 14:39:08 -05:00
Weston Steimel 0c05855131 fix: determine upstream for apk version streams (#1610)
Determines better upstream package name for version-stream apk packages:

Examples:

- postgresql-13 -> postgresql
- postgresql15 -> postgresql
- go-1.19 -> go
- perl100.55 -> perl

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-02-23 17:32:34 +00:00
Weston Steimel 1150772d06 fix: improve CPE generation for curl APK (#1608)
Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-02-23 17:32:12 +00:00
Alex Goodman 669fee84d5 Revert "add workaround for macos github actions cache issue (#1584)" (#1605)
This reverts commit 0076b19893.

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-02-22 15:03:12 -05:00
anchore-actions-token-generator[bot]andwagoodman aa151da5fe Update Stereoscope to fab1c9638abc2c21cd53dca1f205f37d71148ee0 (#1604)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: wagoodman <wagoodman@users.noreply.github.com>
2023-02-22 19:08:35 +00:00
Keith Zantow 4bf677d555 chore: fix cataloger_test (#1603)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-02-22 17:30:41 +00:00
Keith Zantow f5e20521e0 fix: merging of binary packages (#1583) 2023-02-22 12:03:15 -05:00
Keith Zantow 8f6a317fef fix: issue when matching format versions (#1585)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-02-22 10:32:05 -05:00
anchore-actions-token-generator[bot] d339ffdcb5 chore: update syft bootstrap tools to latest versions. (#1593) 2023-02-22 10:16:14 -05:00
Benji Visser e84ffc6003 feat: add perl binary classifier (#1592)
Signed-off-by: Benji Visser <benji@093b.org>
2023-02-22 09:58:05 -05:00
anchore-actions-token-generator[bot] bb52a25c8a Update Stereoscope to 529924d6d5aa6c708cceffc651883b6e1e27f5df (#1602)
Signed-off-by: GitHub <noreply@github.com>
2023-02-22 08:49:04 +00:00
Marc-Etienne Vargenau 4b7b709473 Update SPDX license list to 3.20 (#1600)
Signed-off-by: Marc-Etienne Vargenau <marc-etienne.vargenau@nokia.com>
2023-02-21 15:12:28 -05:00
Keith Zantow 2ef2eed382 chore: update SPDX license list (#1599) 2023-02-21 17:31:24 +00:00
Alex Goodman f6716092af fix cataloger selection to be more specific (#1582)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-02-17 15:35:54 +00:00
Alex Goodman 0076b19893 add workaround for macos github actions cache issue (#1584)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-02-17 10:29:33 -05:00
anchore-actions-token-generator[bot]andwestonsteimel 2642a36161 Update Stereoscope to 4b5ebf8c7f4b81ca79c4c3f0af1d0723eab87d42 (#1576)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: westonsteimel <westonsteimel@users.noreply.github.com>
2023-02-16 10:22:43 -05:00
dependabot[bot] 1981b249f1 chore(deps): bump golang.org/x/net from 0.6.0 to 0.7.0 (#1574)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-15 12:54:55 -05:00
Keith Zantow a3ebb31e3c chore: update bug issue template (#1571)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-02-14 12:58:44 -05:00
Alex Goodman 9b9a7d6c98 allow convert to take stdin (#1570)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-02-14 10:03:47 -05:00
Weston Steimel 57a13ae355 fix: improve CPE and upstream generation logic for Alpine packages (#1567)
* fix: improved CPE-generation logic for alpine packages

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: improved alpine upstream name generation

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: improve CPE vendor for alpine

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: python vendor CPE gen

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: alpine cpe gen logic

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: apk CPE update for nodejs-current

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: CPE update for python pip

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix: CPE update for some ruby packages

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

* fix linting

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>

---------

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-02-13 17:23:13 +00:00
Keith Zantow 890fb3f0e8 fix: missing APK node vulnerabilities (#1565)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-02-10 15:52:13 -05:00
Weston Steimel e236054668 fix: python CPE generation for alpine (#1564)
Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-02-10 18:04:16 +00:00
dependabot[bot] 3013c8b691 chore(deps): bump github.com/docker/docker (#1563)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 23.0.0+incompatible to 23.0.1+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v23.0.0...v23.0.1)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-10 10:43:19 -05:00
Alex Goodman 88c81d33ed switch from trigger-release target to release target (#1560)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-02-09 16:35:11 +00:00
Alex Goodman 988041ba6d Speed up cataloging by replacing globs searching with index lookups (#1510)
* replace raw globs with index equivelent operations

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

* add cataloger test for alpm cataloger

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

* fix import sorting for binary cataloger

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

* fix linting for mock resolver

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

* separate portage cataloger parser impl from cataloger

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

* enhance cataloger pkgtest utils to account for resolver responses

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

* add glob-based cataloger tests for alpm cataloger

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

* add glob-based cataloger tests for apkdb cataloger

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

* add glob-based cataloger tests for dpkg cataloger

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

* add glob-based cataloger tests for cpp cataloger

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

* add glob-based cataloger tests for dart cataloger

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

* add glob-based cataloger tests for dotnet cataloger

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

* add glob-based cataloger tests for elixir cataloger

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

* add glob-based cataloger tests for erlang cataloger

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

* add glob-based cataloger tests for golang cataloger

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

* add glob-based cataloger tests for haskell cataloger

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

* add glob-based cataloger tests for java cataloger

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

* add glob-based cataloger tests for javascript cataloger

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

* add glob-based cataloger tests for php cataloger

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

* add glob-based cataloger tests for portage cataloger

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

* add glob-based cataloger tests for python cataloger

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

* add glob-based cataloger tests for rpm cataloger

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

* add glob-based cataloger tests for rust cataloger

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

* add glob-based cataloger tests for sbom cataloger

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

* add glob-based cataloger tests for swift cataloger

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

* allow generic catloger to run all mimetype searches at once

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

* remove stutter from php and javascript cataloger constructors

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

* bump stereoscope

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

* add tests for generic.Search

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

* add exceptions for java archive git ignore entries

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

* enhance basename and extension resolver methods to be variadic

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

* dont allow * prefix on extension searches

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

* add glob-based cataloger tests for ruby cataloger

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

* remove unnecessary string casting

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

* incorporate surfacing of leaf link resolitions from stereoscope results

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

* [wip] switch to stereoscope file metadata

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

* [wip + failing] revert to old globs but keep new resolvers

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

* index files, links, and dirs within the directory resolver

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

* fix several resolver bugs and inconsistencies

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

* move format testutils to internal package

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

* update syft json to account for file type string normalization

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

* split up directory resolver from indexing

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

* update docs to include details about searching

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

* [wip] bump stereoscope to development version

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

* fix linting

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

* adjust symlinks fixture to be fixed to digest

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

* fix all-locations resolver tests

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

* fix test fixture reference

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

* rename file.Type

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

* bump stereoscope

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

* fix PR comment to exclude extra *

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

* bump to dev version of stereoscope

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

* bump to final version of stereoscope

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

* move observing resolver to pkgtest

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

---------

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-02-09 16:19:47 +00:00
anchore-actions-token-generator[bot] 550e2fc7c3 Update syft bootstrap tools to latest versions. (#1549) 2023-02-09 10:10:35 -05:00
witchcraze 43b53ac173 Fix installed versions (#1556)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2023-02-09 09:03:40 -05:00
dependabot[bot] 08804842fa chore(deps): bump golang.org/x/net from 0.5.0 to 0.6.0 (#1558)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-09 09:01:56 -05:00
witchcrazeandAlex Goodman 284814153d feat: add postgresql classifier (#1536)
* add postgresql classifier
Signed-off-by: witchcraze <witchcraze@gmail.com>

* revert package dedup test upgrade

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

---------

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2023-02-08 14:31:17 -05:00
Alex Goodman 8847ba5d0b Add release trigger (#1501)
* add release trigger

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

* deduplicate version and changelog calls + add gh checks

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

* add more chronicle verbosity, but not when triggering releases

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

* bump chronicle version to get --version-file feature

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

* update bootstrap tool workflow to include glow

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

* add version prefix check on tags in release quality gate

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

---------

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-02-08 11:38:27 -05:00
dependabot[bot] 48528efff3 chore(deps): bump golang.org/x/mod from 0.7.0 to 0.8.0 (#1552)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.7.0 to 0.8.0.
- [Release notes](https://github.com/golang/mod/releases)
- [Commits](https://github.com/golang/mod/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-08 10:07:37 -05:00
dependabot[bot] 8d856a7c7b chore(deps): bump golang.org/x/term from 0.4.0 to 0.5.0 (#1551)
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/term/releases)
- [Commits](https://github.com/golang/term/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-08 09:23:31 -05:00
Avi Deitcher 38a090c218 fix: add support for licenses not found on list (#1540)
Signed-off-by: Avi Deitcher <avi@deitcher.net>
2023-02-07 11:47:04 -05:00
deb7052f41 Update syft bootstrap tools to latest versions. (#1541)
* Update syft bootstrap tools to latest versions.
Signed-off-by: GitHub <noreply@github.com>

* fix: remove ineff assign
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

---------

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-02-07 15:41:14 +00:00
Keith Zantow 9650473298 feat: Allow specific versions of formats to be specified (#1543) 2023-02-07 10:40:43 -05:00
anchore-actions-token-generator[bot]andkzantow 95201840d2 Update Stereoscope to c49244e4d66f1ee789027ea23acc746968799c3b (#1539)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: kzantow <kzantow@users.noreply.github.com>
2023-02-07 10:05:18 -05:00
Justin Chadwell 6ba595344a source: when base is set, responsePath should be absolute (#1542)
When base is set, it should appear identically to when we scan the root
filesystem - and as a result, the path should begin with the path
separator.

E.g. when scanning the root `./target/` with the same base,
`target/bin/busybox` should appear in the output as `/bin/busybox`, not
as previously as `bin/busybox`.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-02-06 12:06:04 -05:00
Christopher Angelo Phillips 9995950c70 fix: update config struct to not decode password/key (#1538)
* fix: update config struct to not decode password/key
* test: update tests to confirm no secrets in output

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
---------

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-02-03 18:06:14 +00:00
anchore-actions-token-generator[bot]andspiffcs b6a496f18c Update syft bootstrap tools to latest versions. (#1537)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2023-02-03 12:35:33 -05:00
witchcraze 0853a50f4d feat: add traefik classifier (#1504)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2023-02-02 13:59:26 -05:00
Nils Hanke a1b82c9664 fix: don't hardcode Cosign attest type (#1533)
Signed-off-by: Nils Hanke <nils.hanke@outlook.de>
2023-02-02 12:47:12 -05:00
dependabot[bot] ad8604c223 chore(deps): bump github.com/docker/docker (#1531)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 20.10.23+incompatible to 23.0.0+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v20.10.23...v23.0.0)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-02 10:53:22 -05:00
anchore-actions-token-generator[bot] d80ee966dc Update syft bootstrap tools to latest versions. (#1530) 2023-02-02 08:47:29 -05:00
Keith Zantow 1530ef354f chore: update spdx/tools-golang to v0.5.0-rc1 (#1503) 2023-01-31 11:53:16 -05:00
Bradley Jones cdac2245b5 feat: update golang to 1.19 (#1526)
* feat: update golang to 1.19

Signed-off-by: Bradley Jones <bradley.jones@anchore.com>

* chore: break out json schema drift check into separate script

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

* chore: update git index refresh

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

---------

Signed-off-by: Bradley Jones <bradley.jones@anchore.com>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-01-31 11:39:57 -05:00
anchore-actions-token-generator[bot] 8dba4c33dd Update syft bootstrap tools to latest versions. (#1525) 2023-01-31 09:27:38 -05:00
Justin Chadwell b81c9805dc Allow scanning unpacked container filesystems (#1485)
* source: avoid second-step of symlink resolution in directory resolver

We can use the already existing file tree to peform symlink resolution
for FilesByPath, instead of traversing the symlinks again.

This moves all of the symlink logic into the indexing code, and then we
can rely on syft's resolution algorithm over the index in this part of
the codebase.

Signed-off-by: Justin Chadwell <me@jedevc.com>

* source: add base parameter to directory resolver

The new base parameter is an optional parameter for the directory
resolver that resolves all symlinks relative to this root. There are two
intended use cases:

- base = "/". The previous behavior, symlinks are resolved relative to
the root filesystem.
- base = path. Symlinks are resolved relative to the target filesystem,
allowing correct behavior when scanning unpacked container filesystems
on disk.

Signed-off-by: Justin Chadwell <me@jedevc.com>

* source: add tests for new base parameter

Signed-off-by: Justin Chadwell <me@jedevc.com>

---------

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-01-30 13:47:24 -05:00
Keith Zantow ba55963104 fix: allow template for syft convert (#1521) 2023-01-26 12:07:36 -05:00
Christopher Angelo Phillips 8c91605541 1465 attestation with private key (#1502)
1465 attestation with private key (#1502)

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-01-26 11:19:13 -05:00
Weston Steimel 4c0aef09b8 fix: add relevant CPEs to python and busybox classifiers (#1517)
Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-01-25 17:18:24 +00:00
anchore-actions-token-generator[bot] 02fb757c21 Update syft bootstrap tools to latest versions. (#1515) 2023-01-25 10:31:53 -05:00
Keith Zantow 674a54512c chore: correct bootstrap tool script (#1514) 2023-01-25 10:22:28 -05:00
dependabot[bot] 21ba5d0806 chore(deps): bump github.com/google/go-containerregistry (#1513)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.12.1 to 0.13.0.
- [Release notes](https://github.com/google/go-containerregistry/releases)
- [Changelog](https://github.com/google/go-containerregistry/blob/main/.goreleaser.yml)
- [Commits](https://github.com/google/go-containerregistry/compare/v0.12.1...v0.13.0)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-25 13:41:43 +00:00
Alex GoodmanandKeith Zantow 0ba57a5936 Fix AssertEncoderAgainstGoldenSnapshot calls to conditionally update (#1511)
* fix AssertEncoderAgainstGoldenSnapshot calls to conditionally update

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

* chore: redact schema versions from syftjson comparison

Signed-off-by: Keith Zantow <kzantow@gmail.com>

* chore: does not need a multiline expression

Signed-off-by: Keith Zantow <kzantow@gmail.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2023-01-24 21:41:57 +00:00
dependabot[bot] 3269bc98d4 chore(deps): bump golang.org/x/mod from 0.6.0 to 0.7.0 (#1505)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/mod/releases)
- [Commits](https://github.com/golang/mod/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-23 15:01:25 -05:00
dependabot[bot] 7f3382f7eb chore(deps): bump github.com/docker/docker (#1506)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 20.10.20+incompatible to 20.10.23+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v20.10.20...v20.10.23)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-23 14:58:39 -05:00
dependabot[bot] 65e5ff63f0 chore(deps): bump github.com/Masterminds/sprig/v3 from 3.2.2 to 3.2.3 (#1507)
Bumps [github.com/Masterminds/sprig/v3](https://github.com/Masterminds/sprig) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/Masterminds/sprig/releases)
- [Changelog](https://github.com/Masterminds/sprig/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Masterminds/sprig/compare/v3.2.2...v3.2.3)

---
updated-dependencies:
- dependency-name: github.com/Masterminds/sprig/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-23 14:48:22 -05:00
dependabot[bot] d287c22b69 chore(deps): bump github.com/dustin/go-humanize from 1.0.0 to 1.0.1 (#1508)
Bumps [github.com/dustin/go-humanize](https://github.com/dustin/go-humanize) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/dustin/go-humanize/releases)
- [Commits](https://github.com/dustin/go-humanize/compare/v1.0.0...v1.0.1)

---
updated-dependencies:
- dependency-name: github.com/dustin/go-humanize
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-23 14:48:00 -05:00
Luca Comellini e8be93a8eb Bump github.com/spdx/tools-golang to v0.4.0 (#1450)
Signed-off-by: Luca Comellini <luca.com@gmail.com>
2023-01-20 17:00:21 -05:00
Dan LuhringandAlex Goodman e58050bac0 Fix panic in apkdb parsing on empty "provides" values (#1494)
* Add failing test for strip version specifiers panic

Signed-off-by: Dan Luhring <dluhring@chainguard.dev>

* Fix test

Signed-off-by: Dan Luhring <dluhring@chainguard.dev>

* Prevent panic scenario in helper func

Signed-off-by: Dan Luhring <dluhring@chainguard.dev>

* Fix lint issue

Signed-off-by: Dan Luhring <dluhring@chainguard.dev>

* add tests for apk stripVersionSpecifier() and remove caller empty value check

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

Signed-off-by: Dan Luhring <dluhring@chainguard.dev>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-20 14:49:44 +00:00
Alex Goodman 36a0945c95 push detailed log statements to trace-level (#1500)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-20 14:33:23 +00:00
mikcl 396441e921 npm: package-lock license decoding to accept string or array (#1482)
Signed-off-by: mikcl <mikesmikes400@gmail.com>
2023-01-20 09:28:51 -05:00
Alex Goodman 972e4cdaeb always set the package ID for java packages (#1493)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-20 09:18:00 -05:00
Nils Hanke 99f55f6a81 fix: skip filling in empty fields in APK metadata (#1484)
Signed-off-by: Nils Hanke <nils.hanke@outlook.de>

Signed-off-by: Nils Hanke <nils.hanke@outlook.de>
2023-01-20 14:03:30 +00:00
dependabot[bot] 285112fe29 chore(deps): bump github.com/facebookincubator/nvdtools (#1499)
Bumps [github.com/facebookincubator/nvdtools](https://github.com/facebookincubator/nvdtools) from 0.1.4 to 0.1.5.
- [Release notes](https://github.com/facebookincubator/nvdtools/releases)
- [Commits](https://github.com/facebookincubator/nvdtools/compare/v0.1.4...v0.1.5)

---
updated-dependencies:
- dependency-name: github.com/facebookincubator/nvdtools
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-20 14:02:47 +00:00
dependabot[bot] f29bea5921 chore(deps): bump github.com/jinzhu/copier from 0.3.2 to 0.3.5 (#1498)
Bumps [github.com/jinzhu/copier](https://github.com/jinzhu/copier) from 0.3.2 to 0.3.5.
- [Release notes](https://github.com/jinzhu/copier/releases)
- [Commits](https://github.com/jinzhu/copier/compare/v0.3.2...v0.3.5)

---
updated-dependencies:
- dependency-name: github.com/jinzhu/copier
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-20 08:51:20 -05:00
dependabot[bot] 39cdbc42aa chore(deps): bump github.com/vbatts/go-mtree from 0.5.0 to 0.5.2 (#1497)
Bumps [github.com/vbatts/go-mtree](https://github.com/vbatts/go-mtree) from 0.5.0 to 0.5.2.
- [Release notes](https://github.com/vbatts/go-mtree/releases)
- [Changelog](https://github.com/vbatts/go-mtree/blob/main/releases.md)
- [Commits](https://github.com/vbatts/go-mtree/compare/v0.5.0...v0.5.2)

---
updated-dependencies:
- dependency-name: github.com/vbatts/go-mtree
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-20 08:50:59 -05:00
dependabot[bot] 27b62ce833 chore(deps): bump github.com/gookit/color from 1.4.2 to 1.5.2 (#1496)
Bumps [github.com/gookit/color](https://github.com/gookit/color) from 1.4.2 to 1.5.2.
- [Release notes](https://github.com/gookit/color/releases)
- [Commits](https://github.com/gookit/color/compare/v1.4.2...v1.5.2)

---
updated-dependencies:
- dependency-name: github.com/gookit/color
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-20 08:50:37 -05:00
dependabot[bot] 499e7c4e16 chore(deps): bump github.com/spf13/viper from 1.14.0 to 1.15.0 (#1495)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.14.0...v1.15.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-20 08:50:19 -05:00
Alex GoodmanandChristopher Phillips 0f75f975c8 Relax error conditions for catalogers (#1492)
* binary cataloger should continue on errors

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

* test: add redirect for cmd stderr stdout

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

* test: image update for test failure

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-01-19 19:28:42 -05:00
witchcraze 7427445fe9 feat: add memcached classifier (#1486)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2023-01-19 11:22:11 -05:00
dependabot[bot] 09a5baf523 chore(deps): bump github.com/spf13/viper from 1.13.0 to 1.14.0 (#1488)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.13.0...v1.14.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-19 10:39:04 -05:00
dependabot[bot] 33c08c8545 chore(deps): bump github.com/bmatcuk/doublestar/v4 from 4.0.2 to 4.6.0 (#1489)
Bumps [github.com/bmatcuk/doublestar/v4](https://github.com/bmatcuk/doublestar) from 4.0.2 to 4.6.0.
- [Release notes](https://github.com/bmatcuk/doublestar/releases)
- [Commits](https://github.com/bmatcuk/doublestar/compare/v4.0.2...v4.6.0)

---
updated-dependencies:
- dependency-name: github.com/bmatcuk/doublestar/v4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-19 10:38:50 -05:00
dependabot[bot] fd002db802 chore(deps): bump github.com/spf13/cobra from 1.6.0 to 1.6.1 (#1490)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.6.0...v1.6.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-19 14:16:50 +00:00
dependabot[bot] cb3e4b8e49 chore(deps): bump github.com/go-test/deep from 1.0.8 to 1.1.0 (#1491)
Bumps [github.com/go-test/deep](https://github.com/go-test/deep) from 1.0.8 to 1.1.0.
- [Release notes](https://github.com/go-test/deep/releases)
- [Changelog](https://github.com/go-test/deep/blob/master/CHANGES.md)
- [Commits](https://github.com/go-test/deep/compare/v1.0.8...v1.1.0)

---
updated-dependencies:
- dependency-name: github.com/go-test/deep
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-19 14:01:33 +00:00
dependabot[bot] 5917f8d8f9 chore(deps): bump github.com/google/go-containerregistry (#1487)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.11.0 to 0.12.1.
- [Release notes](https://github.com/google/go-containerregistry/releases)
- [Changelog](https://github.com/google/go-containerregistry/blob/main/.goreleaser.yml)
- [Commits](https://github.com/google/go-containerregistry/compare/v0.11.0...v0.12.1)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-19 13:47:36 +00:00
dependabot[bot] 70e6d0f2e3 chore(deps): bump golang.org/x/net from 0.4.0 to 0.5.0 (#1475)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-18 14:39:50 +00:00
dependabot[bot] 31a763c46d chore(deps): bump github.com/adrg/xdg from 0.3.3 to 0.4.0 (#1477)
Bumps [github.com/adrg/xdg](https://github.com/adrg/xdg) from 0.3.3 to 0.4.0.
- [Release notes](https://github.com/adrg/xdg/releases)
- [Commits](https://github.com/adrg/xdg/compare/v0.3.3...v0.4.0)

---
updated-dependencies:
- dependency-name: github.com/adrg/xdg
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-18 09:39:35 -05:00
dependabot[bot] ae6c9c2e97 chore(deps): bump github.com/sergi/go-diff from 1.2.0 to 1.3.1 (#1476)
Bumps [github.com/sergi/go-diff](https://github.com/sergi/go-diff) from 1.2.0 to 1.3.1.
- [Release notes](https://github.com/sergi/go-diff/releases)
- [Commits](https://github.com/sergi/go-diff/compare/v1.2.0...v1.3.1)

---
updated-dependencies:
- dependency-name: github.com/sergi/go-diff
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-18 09:39:15 -05:00
dependabot[bot] f6a0dd33d1 chore(deps): bump github.com/vifraa/gopom from 0.1.0 to 0.2.1 (#1474)
Bumps [github.com/vifraa/gopom](https://github.com/vifraa/gopom) from 0.1.0 to 0.2.1.
- [Release notes](https://github.com/vifraa/gopom/releases)
- [Commits](https://github.com/vifraa/gopom/compare/v0.1.0...v0.2.1)

---
updated-dependencies:
- dependency-name: github.com/vifraa/gopom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-18 09:38:30 -05:00
dependabot[bot] b77c104aa6 chore(deps): bump github/codeql-action from 1 to 2 (#1473)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-18 09:38:06 -05:00
dependabot[bot] 10ca7f56ab chore(deps): bump actions/setup-go from 2 to 3 (#1472)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-18 09:37:45 -05:00
Luca Comellini 6b2dc08ffb Add dependabot (#1451)
Signed-off-by: Luca Comellini <luca.com@gmail.com>

Signed-off-by: Luca Comellini <luca.com@gmail.com>
2023-01-18 09:29:24 -05:00
Christopher Angelo Phillips 03971ace43 chore: use checkout v3 with new depth (#1471) 2023-01-17 21:26:39 +00:00
Christopher Angelo Phillips 07aee798b0 chore: use checkout v2 for tag depth (#1470) 2023-01-17 21:03:29 +00:00
Keith ZantowandAlex Goodman 6cf668f749 fix: nil panic in graalvm cataloger (#1468)
* normalize error handling and recover from panics while parsing binaries
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-17 19:06:24 +00:00
Alex Goodman 2ec4371c95 add linter for type assertion checks (#1469)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-17 14:00:03 -05:00
Weston Steimel fc4d28f365 fix: bump golang.org/x/net to v0.4.0 (#1467)
resolves reporting of CVE-2022-41717

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-01-17 17:02:34 +00:00
Weston Steimel 5290dfb9c2 fix: bump golang.org/x/text to v0.3.8 (#1466)
This resolves reporting of GHSA-69ch-w2m2-3vjp

Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-01-17 15:50:02 +00:00
Alex Goodman 05611c283d bootstrap within composite action (#1461)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-17 10:04:22 -05:00
Keith Zantow 934644232a chore: revert GolangBinMetadata name and make analogous GolangModMetadata (#1458) 2023-01-13 16:46:12 -05:00
Florian Klink 641bccc79b README: update Nix installation instructions (#1455)
22.05 has been released, update the instructions.

Signed-off-by: Florian Klink <flokli@flokli.de>
2023-01-13 15:43:25 +00:00
Keith Zantow ac94bf530c fix: update graalvm cataloger to fix panic (#1454)
Fixes https://github.com/anchore/syft/issues/1453
2023-01-12 17:42:13 -05:00
Weston Steimel e87cfe7319 chore: remove bumping cosign in go.mod when updating bootstrap tools (#1452) 2023-01-12 16:21:01 -05:00
Asi GreenholtsandAlex Goodman 260cb4c72d feat: Add the origin field to the output format of syftjson (#1327)
* moved the relevant fields to the Metadata field

Signed-off-by: Asaf Greenholts <asaf@cidersecurity.io>

* added metadata types

Signed-off-by: Asaf Greenholts <asaf@cidersecurity.io>

* Added hashes to metadata of packge-lock.json and Pipfile.lock

Signed-off-by: Asaf Greenholts <asaf@cidersecurity.io>

* move package metadata types to "pkg" package

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

* re-generate json schema to include new npm, python, and binary metadatas

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

Signed-off-by: Asaf Greenholts <asaf@cidersecurity.io>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-12 15:03:05 -05:00
Keith Zantow 85bddaa43d chore: update schema (#1449) 2023-01-12 14:25:47 -05:00
Arnout EngelenandAlex Goodman a864dc9505 feat: prefer known CPE vendors over other candidates (#1294)
* feat: prefer known CPE vendors over other candidates

All ASF projects will be under the `apache` vendor in CPE, and
indeed this is already one of the candidates, but the logic
for selecting the 'most specific' CPE string would select for
example `apache_software_foundation` or `commons-text`.

This is not necessarily 'wrong' in the CPE candidate selection
logic: there is no way to reliably determine the right candidate.
I think it makes sense to use specific data around the vendor
candidate generation, somewhat similar to
'defaultCandidateAdditions'.

Unfortunately there are still a few CVE's for old (pre-5.x,
long unsupported) tomcat versions that are actually tagged with
`apache_software_foundation`, but I'm not sure those are worth
spending time on.

Signed-off-by: Arnout Engelen <arnout@bzzt.net>

* chore: swap out array of vendors for set data structure

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

Signed-off-by: Arnout Engelen <arnout@bzzt.net>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-12 19:16:53 +00:00
Christopher Angelo PhillipsandAlex Goodman 44e8ae2577 fix: update attestation code to remove library dependencies and shellout for keyless flow (#1442)
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-12 17:22:05 +00:00
Chapman PenderyandAlex Goodman ac8f72fdd1 feat: add BeamVM Hex support (#1073)
* feat: initial commit providing mix support

Signed-off-by: cpendery <cpendery@vt.edu>

* feat: add rebar parser

Signed-off-by: cpendery <cpendery@vt.edu>

* fix: add beam/hex everywhere else required for Syft runtime

Signed-off-by: cpendery <cpendery@vt.edu>

* style: fix lints

Signed-off-by: cpendery <cpendery@vt.edu>

* ci: fix failing tests

Signed-off-by: cpendery <cpendery@vt.edu>

* docs: update with new supported languages

Signed-off-by: cpendery <cpendery@vt.edu>

* chore: update elixir/erlang catalogers to generic cataloger

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

Signed-off-by: cpendery <cpendery@vt.edu>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-12 12:10:46 -05:00
witchcraze e063471c66 feat: add apache httpd binary classifier (#1448)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2023-01-12 10:50:01 -05:00
Batuhan Apaydın 645debe7a4 chore: claim artifacthub package ownership from developer-guy (#881)
Signed-off-by: Batuhan Apaydın <batuhan.apaydin@trendyol.com>

Signed-off-by: Batuhan Apaydın <batuhan.apaydin@trendyol.com>
2023-01-11 15:25:42 -05:00
mikclandAlex Goodman 4bfb849310 Parallel package catalog processing (#1355)
* catalog: run cataloggers concurrently

Signed-off-by: mikcl <mikesmikes400@gmail.com>

* frontend: expose workers as a configurable option

Signed-off-by: mikcl <mikesmikes400@gmail.com>

* fixup! frontend: expose workers as a configurable option

Signed-off-by: mikcl <mikesmikes400@gmail.com>

* update logging statements

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

* test: assert for debug logging

Signed-off-by: mikcl <mikesmikes400@gmail.com>

Signed-off-by: mikcl <mikesmikes400@gmail.com>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2023-01-11 15:18:02 -05:00
witchcraze d524bd5fc3 feat: Add php binary catalogers (#1444)
* add php classifier
Signed-off-by: witchcraze <witchcraze@gmail.com>

* make lint-fix
Signed-off-by: witchcraze <witchcraze@gmail.com>
2023-01-11 13:46:20 -05:00
anchore-actions-token-generator[bot]andspiffcs a8416d674b Update syft bootstrap tools to latest versions. (#1443)
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2023-01-11 12:50:40 -05:00
Keith Zantow 725529f43f fix: duplicate file in tar archive causes read to fail (#1445) 2023-01-10 14:55:02 -05:00
William Blair e480443c8c Add support for GraalVM Native Image executables. (#1276)
Signed-off-by: William Blair <william.blair@oracle.com>
2023-01-06 18:31:22 -05:00
Benji Visser db386baf81 Add redis binary classifier (#1438)
Signed-off-by: Benji Visser <benji@093b.org>
2023-01-06 12:50:48 -05:00
Christopher Angelo Phillips 795a63f1c9 docs: add cataloger construction summary (#1434) 2023-01-05 17:03:00 +00:00
anchore-actions-token-generator[bot] d4f9993b8d chore: update bootstrap tools to latest versions. (#1428) 2023-01-05 10:20:58 -05:00
Benji Visser bb6fc6525c Add alpine type to purl (#1431)
Signed-off-by: Benji Visser <benji@093b.org>
2023-01-04 17:35:46 -05:00
Benji Visser bc1edb9c8a adding purl types for binary classifiers (#1435)
Signed-off-by: Benji Visser <benji@093b.org>
2023-01-04 11:34:37 -05:00
Keith Zantow 64be0a1072 chore: refactor basic CPE functionality to its own package (#1436) 2023-01-04 11:26:28 -05:00
Justin Chadwell e3d6ffd30e fix: typo in os.Getwd error message (#1433)
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-01-03 14:56:20 +00:00
Justin Chadwell 8d36b21237 fix: additional excessive go binary warnings (#1432)
The original fix b125ea83ba didn't catch
all the excessive warnings, it seems like getArches can also be called
on binaries that aren't neccessarily go binaries, so the messages from
this should also be Trace instead of Warn.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-01-03 09:54:08 -05:00
Rui Chen 6a7d6e6071 docs: migrate to homebrew-core (#1427) 2023-01-02 08:16:32 -05:00
Keith Zantow e1e489a284 fix: unicode output in cyclonedx-json format (#1420) 2022-12-23 08:37:47 -05:00
Keith Zantow b125ea83ba fix: excessive go binary warnings (#1424) 2022-12-23 08:36:49 -05:00
Christopher Angelo Phillips 3690f979b3 feat: update spdx format model to produce valid spdx json documents (#1418) 2022-12-21 15:56:03 -05:00
Alex Goodman 5dd726fc86 clean package names in python parsers (#1417)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-12-21 18:31:49 +00:00
Christopher Angelo Phillips c8b8b1ca11 docs: update schema name to 2.3 (#1416) 2022-12-20 02:57:19 +00:00
Keith Zantow 7b08608adb feat: add h1digest when scanning go.mod (#1405)
Fixes https://github.com/anchore/syft/issues/1277
2022-12-20 02:18:35 +00:00
dja-fr 82f32c7301 feat: Add license parsing for java (#1385) 2022-12-19 20:10:15 -05:00
Keith Zantow 4ffbeeeea5 fix: cyclonedx component type for binaries (#1406) 2022-12-19 19:49:27 -05:00
Keith Zantow b1d6dae203 fix: openjdk detection pattern (#1415) 2022-12-19 19:49:04 -05:00
Christopher Angelo Phillips 0f1e8fca14 bug: spdx checksum empty array; allow syft to generate SHA1 for spdx-tag-value documents (#1404) 2022-12-20 00:10:35 +00:00
Thomas Klausner 8b38549b79 Add NetBSD support. (#1412) 2022-12-19 16:59:50 -05:00
Christopher Angelo Phillips 23a3173c9f feat: add catalog delete (#1377) 2022-12-12 12:55:12 -05:00
Keith Zantow 17aa8287e6 docs: remove file classifier (#1397) 2022-12-08 16:50:29 +00:00
Christopher Angelo Phillips 730d3e3187 chore: update latest cyclonedx library (#1390) 2022-12-08 11:36:08 -05:00
Keith Zantow 997fbdfcf3 feat: Add Java binary catalogers (#1392) 2022-12-08 10:50:28 -05:00
Marc-Etienne Vargenau 13ceed9336 chore: Update SPDX license list to 3.19 (#1389) 2022-12-08 10:29:27 -05:00
Chapman Pendery 668f102340 fix: add manual vendor/product removal to fix false flags (#1070)
Closes https://github.com/anchore/syft/issues/1066
Closes https://github.com/anchore/grype/issues/800
Closes https://github.com/anchore/grype/issues/491
2022-12-08 09:57:42 -05:00
anchore-actions-token-generator[bot] f1a124209a Update Stereoscope to c5ff155d72f166e2332e160a75c3ff2b8e9c7e2e (#1395)
Signed-off-by: GitHub <noreply@github.com>
2022-12-08 08:32:49 +00:00
Keith Zantow 5dbb3fc41d chore: fix test busybox image sha (#1393) 2022-12-07 20:15:39 -05:00
Keith Zantow 614ea00905 fix: go version not properly identified in binary (#1384) 2022-12-02 13:24:36 -05:00
anchore-actions-token-generator[bot]andwagoodman 247b054ab5 Update Stereoscope to 3b80d983223f6e6fc2d33b0ffa003d30268418e9 (#1376)
Signed-off-by: GitHub <noreply@github.com>

Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: wagoodman <wagoodman@users.noreply.github.com>
2022-11-30 16:11:57 +00:00
Keith Zantow 9e43725951 fix: Update node binary package name (#1375) 2022-11-30 10:30:57 -05:00
Keith Zantow 4f39287216 feat: Generic Binary Cataloger (#1336) 2022-11-29 18:28:10 -05:00
Alex Goodman 7a69e2129b recover from bad parsing of golang binary (#1371)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-29 15:56:46 +00:00
Dan Luhring f6996f7b9a Fix parsing of apk databases with large entries (#1365)
Closes https://github.com/anchore/syft/issues/1354
2022-11-29 10:16:36 -05:00
anchore-actions-token-generator[bot]andspiffcs bd523bdb5d Update syft bootstrap tools to latest versions. (#1369)
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2022-11-29 10:13:00 -05:00
Christopher Angelo Phillips 0cbd0cc703 fix: guard for locations < 1 in alpmdb parse (#1366) 2022-11-28 15:43:18 +00:00
Christopher Angelo Phillips b290a445ca fix: remove cabal.project.freeze panic on last pkg (#1363) 2022-11-23 22:33:18 +00:00
Christopher Angelo Phillips bcfe38c009 fix: requirements.txt - return unicode only letter/num for version (#1361) 2022-11-22 10:43:05 -05:00
anchore-actions-token-generator[bot]andspiffcs 74967a28ea Update syft bootstrap tools to latest versions. (#1356)
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2022-11-21 09:57:49 -05:00
Keith Zantow 098e61dcc8 fix: sort relationships in SPDX output (#1350) 2022-11-21 09:26:24 -05:00
Keith Zantow 0dddf51fd5 chore: add debug logging for decode errors (#1352) 2022-11-21 09:26:11 -05:00
mikcl 04880c06ce feat(npm): handle aliases in package-lock.json (#1349) 2022-11-20 11:32:10 -05:00
Christopher Angelo Phillips da4b2df576 fix: spdx java checksum correctness (#1348) 2022-11-18 13:42:55 -05:00
Rob Cresswell 9d8244bae6 feat: Add support for npm lockfile version 3 (#1206)
This PR adds support for npm lockfile version 3, which drops the
"dependencies" key and uses "packages" instead. I've refactored the
lockfile parser to make the distinction between the versions explicit
rather than the implicit behaviour before. It _might_ be worth splitting
into separate files at some point, but the logic is so minimal that I
haven't done it.

Fixes #1203
Signed-off-by: Rob Cresswell <robcresswell@users.noreply.github.com>
2022-11-18 12:41:31 -05:00
Christopher Angelo Phillips 67888ee855 1111 clean name bug (#1347) 2022-11-18 14:45:18 +00:00
Alex GoodmanandKeith Zantow 9afc9231c0 Add spdx relationship encoding for dependencies (#1342)
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2022-11-18 09:40:10 -05:00
Keith Zantow 42cb0a47a4 feat: SPDX 2.3 support (#1311) 2022-11-18 08:54:39 -05:00
0c4b99c1c2 SBOM cataloger (#1029)
* SBOM cataloger

Signed-off-by: Patrik Beno <patrik.beno@greenhorn.sk>

* sbom-cataloger: turn off by default

and add integration test

Signed-off-by: Patrik Beno <patrik.beno@greenhorn.sk>

* SBOM cataloger

Signed-off-by: Patrik Beno <patrik.beno@greenhorn.sk>

* SBOM cataloger (optimize)

Signed-off-by: Patrik Beno <patrik.beno@greenhorn.sk>

* SBOM cataloger (fix)

Signed-off-by: Patrik Beno <patrik.beno@greenhorn.sk>

* SBOM cataloger (fix imports #1172)

Signed-off-by: Patrik Beno <patrik.beno@greenhorn.sk>

* SBOM cataloger (fix: support group attribute in CDX SBOMs)

Signed-off-by: Patrik Beno <patrik.beno@greenhorn.sk>

* port to generic cataloger and add relationship to original file

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

* generalize parser for all format globs

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

Signed-off-by: Patrik Beno <patrik.beno@greenhorn.sk>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Tom Fay <tomfay@microsoft.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-16 14:11:45 -05:00
Christopher Angelo Phillips 0774ad15e2 chore: clean up linting configuration (#1343) 2022-11-16 16:28:09 +00:00
Keith Zantow f8be64d312 fix: Unmarshal Syft JSON with missing metadata (#1338) 2022-11-15 13:00:10 -05:00
Alex Goodman 1ae577a035 fix apk decode for older data shapes (#1341)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-15 16:38:31 +00:00
Weston Steimel 09bf5b062c chore: add unit test for wolfi os release identification (#1340)
Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2022-11-14 18:57:31 -05:00
Keith Zantow c1fdfce5f1 fix: Output only valid CPEs for CycloneDX OS components (#1339) 2022-11-14 15:24:19 -05:00
Justin Chadwell 10f43d75e0 feat: Add --name option to override name in output (#1269) 2022-11-10 14:03:23 -05:00
949cff158d Add support for dependency relationships for alpine (apk) (#1063)
* Fix type of pull deps and add support for provides

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* [wip] apk dependency lookup

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

* update whitespace for linter

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

* adjust test conditions

Signed-off-by: Timothy Gerla <tim@gerla.net>

* fix TODOs and improve Provides parser

* run simports after main merge

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

* add tests to cover apk relationship parsing cases

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

* generate JSON schema for breaking changes to apk metadata

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

* update tests to account for additional dependencies

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

* [wip] fix relationship encoding for cyclonedx

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

* simplify package relationships that can be expressed

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

Signed-off-by: Dan Luhring <dan+github@luhrings.com>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Signed-off-by: Timothy Gerla <tim@gerla.net>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
Co-authored-by: Timothy Gerla <tim@gerla.net>
2022-11-09 15:43:37 +00:00
Alex Goodman e58d0aecb8 normalize alpm md5 refs (#1333)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-09 15:04:15 +00:00
Alex Goodman d7a51a69dd Update java generic cataloger (#1329)
* remove centralize pURL generation

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

* port java cataloger to new generic cataloger pattern

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

* remove common.GenericCataloger

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

* update format test fixtures to reflect ID updates

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

* fix package sort instability for encode-decode-encode cycles

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

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-09 14:55:54 +00:00
Keith Zantow f3528132a7 Support encoding map types to CycloneDX properties (#1332) 2022-11-08 18:59:37 -05:00
Alex Goodman 5ed002e1a9 Update swift cataloger to generic cataloger (#1324)
* port swift cataloger to new generic cataloger pattern

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

* add cocopods metadata to json schema defs

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

* update json test fixture with latest schema version

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

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-04 13:51:59 -04:00
Alex Goodman f319713821 port rust cataloger to new generic cataloger pattern (#1323)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-04 16:07:36 +00:00
Alex Goodman 41464bbd7f port ruby cataloger to new generic cataloger pattern (#1322)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-04 11:33:55 -04:00
Alex Goodman 3048382bbd port rpm cataloger to new generic cataloger pattern (#1321)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-04 10:41:04 -04:00
Alex Goodman 1076281566 port python cataloger to new generic cataloger pattern (#1319)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-04 08:59:03 -04:00
Alex Goodman 2deb96a801 Update portage cataloger to new generic cataloger (#1316)
* port portage (ha) cataloger to new generic cataloger pattern

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

* update JSON schema to account for removing portage fields

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

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-03 14:49:18 -04:00
Alex Goodman 891f2c576b port php cataloger to new generic cataloger pattern (#1315)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-03 13:00:44 -04:00
Kenny MoensandKeith Zantow bc9740d50a javascript cataloger: node binary: nil pointer dereference (#1313)
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2022-11-03 14:38:49 +00:00
Keith Zantow 3e99c4d7d8 Fix: Include version information in binary cataloger CPEs (#1310) 2022-11-03 10:17:15 -04:00
Christopher Angelo Phillips 10464642e9 fix: only generate PURL on empty string (#1312) 2022-11-03 10:00:14 -04:00
Alex Goodman e0acfa98c7 add s3 credentials to release (#1309)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-02 15:48:37 +00:00
Alex Goodman 9634b42746 port javascript cataloger to new generic cataloger pattern (#1308)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2022-11-02 11:31:57 -04:00
731 changed files with 455155 additions and 20630 deletions
+2 -2
View File
@@ -7,12 +7,12 @@ assignees: ''
---
**Please provide a set of steps on how to reproduce the issue**
**What happened**:
**What you expected to happen**:
**Steps to reproduce the issue**:
**Anything else we need to know?**:
**Environment**:
+81
View File
@@ -0,0 +1,81 @@
name: "Bootstrap"
description: "Bootstrap all tools and dependencies"
inputs:
go-version:
description: "Go version to install"
required: true
default: "1.19.x"
use-go-cache:
description: "Restore go cache"
required: true
default: "true"
cache-key-prefix:
description: "Prefix all cache keys with this value"
required: true
default: "831180ac25"
build-cache-key-prefix:
description: "Prefix build cache key with this value"
required: true
default: "f8b6d31dea"
bootstrap-apt-packages:
description: "Space delimited list of tools to install via apt"
default: "libxml2-utils"
runs:
using: "composite"
steps:
- uses: actions/setup-go@v3
with:
go-version: ${{ inputs.go-version }}
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
# note: we need to keep restoring the go mod cache before bootstrapping tools since `go install` is used in
# some installations of project tools.
- name: Restore go module cache
id: go-mod-cache
if: inputs.use-go-cache == 'true'
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-go-${{ inputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ inputs.cache-key-prefix }}-${{ runner.os }}-go-${{ inputs.go-version }}-
- name: (cache-miss) Bootstrap project tools
shell: bash
if: steps.tool-cache.outputs.cache-hit != 'true'
run: make bootstrap-tools
- name: Restore go build cache
id: go-cache
if: inputs.use-go-cache == 'true'
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
key: ${{ inputs.cache-key-prefix }}-${{ inputs.build-cache-key-prefix }}-${{ runner.os }}-go-${{ inputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ inputs.cache-key-prefix }}-${{ inputs.build-cache-key-prefix }}-${{ runner.os }}-go-${{ inputs.go-version }}-
- name: (cache-miss) Bootstrap go dependencies
shell: bash
if: steps.go-mod-cache.outputs.cache-hit != 'true' && inputs.use-go-cache == 'true'
run: make bootstrap-go
- name: Install apt packages
if: inputs.bootstrap-apt-packages != ''
shell: bash
run: |
DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y ${{ inputs.bootstrap-apt-packages }}
- name: Create all cache fingerprints
shell: bash
run: make fingerprints
+10
View File
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: daily
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: daily
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
red=$(tput setaf 1)
bold=$(tput bold)
normal=$(tput sgr0)
# assert we are running in CI (or die!)
if [[ -z "$CI" ]]; then
echo "${bold}${red}This step should ONLY be run in CI. Exiting...${normal}"
exit 1
fi
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env python3
import subprocess
import sys
import shlex
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
if len(sys.argv) < 3:
print("Usage: coverage.py [threshold] [go-coverage-report]")
sys.exit(1)
threshold = float(sys.argv[1])
report = sys.argv[2]
args = shlex.split(f"go tool cover -func {report}")
p = subprocess.run(args, capture_output=True, text=True)
percent_coverage = float(p.stdout.splitlines()[-1].split()[-1].replace("%", ""))
print(f"{bcolors.BOLD}Coverage: {percent_coverage}%{bcolors.ENDC}")
if percent_coverage < threshold:
print(f"{bcolors.BOLD}{bcolors.FAIL}Coverage below threshold of {threshold}%{bcolors.ENDC}")
sys.exit(1)
+6 -7
View File
@@ -4,19 +4,18 @@ set -eu
ORIGINAL_STATE_DIR=$(mktemp -d "TEMP-original-state-XXXXXXXXX")
TIDY_STATE_DIR=$(mktemp -d "TEMP-tidy-state-XXXXXXXXX")
trap "cp -v ${ORIGINAL_STATE_DIR}/* ./ && rm -fR ${ORIGINAL_STATE_DIR} ${TIDY_STATE_DIR}" EXIT
trap "cp -p ${ORIGINAL_STATE_DIR}/* ./ && git update-index -q --refresh && rm -fR ${ORIGINAL_STATE_DIR} ${TIDY_STATE_DIR}" EXIT
echo "Capturing original state of files..."
cp -v go.mod go.sum "${ORIGINAL_STATE_DIR}"
# capturing original state of files...
cp go.mod go.sum "${ORIGINAL_STATE_DIR}"
echo "Capturing state of go.mod and go.sum after running go mod tidy..."
# capturing state of go.mod and go.sum after running go mod tidy...
go mod tidy
cp -v go.mod go.sum "${TIDY_STATE_DIR}"
echo ""
cp go.mod go.sum "${TIDY_STATE_DIR}"
set +e
# Detect difference between the git HEAD state and the go mod tidy state
# detect difference between the git HEAD state and the go mod tidy state
DIFF_MOD=$(diff -u "${ORIGINAL_STATE_DIR}/go.mod" "${TIDY_STATE_DIR}/go.mod")
DIFF_SUM=$(diff -u "${ORIGINAL_STATE_DIR}/go.sum" "${TIDY_STATE_DIR}/go.sum")
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -u
if ! git diff-index --quiet HEAD --; then
git diff-index HEAD --
git --no-pager diff
echo "there are uncommitted changes, please commit them before running this check"
exit 1
fi
success=true
if ! make generate-json-schema; then
echo "Generating json schema failed"
success=false
fi
if ! git diff-index --quiet HEAD --; then
git diff-index HEAD --
git --no-pager diff
echo "JSON schema drift detected!"
success=false
fi
if ! $success; then
exit 1
fi
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -eu
bold=$(tput bold)
normal=$(tput sgr0)
if ! [ -x "$(command -v gh)" ]; then
echo "The GitHub CLI could not be found. To continue follow the instructions at https://github.com/cli/cli#installation"
exit 1
fi
gh auth status
# we need all of the git state to determine the next version. Since tagging is done by
# the release pipeline it is possible to not have all of the tags from previous releases.
git fetch --tags
# populates the CHANGELOG.md and VERSION files
echo "${bold}Generating changelog...${normal}"
make changelog 2> /dev/null
NEXT_VERSION=$(cat VERSION)
if [[ "$NEXT_VERSION" == "" || "${NEXT_VERSION}" == "(Unreleased)" ]]; then
echo "Could not determine the next version to release. Exiting..."
exit 1
fi
while true; do
read -p "${bold}Do you want to trigger a release for version '${NEXT_VERSION}'?${normal} [y/n] " yn
case $yn in
[Yy]* ) echo; break;;
[Nn]* ) echo; echo "Cancelling release..."; exit;;
* ) echo "Please answer yes or no.";;
esac
done
echo "${bold}Kicking off release for ${NEXT_VERSION}${normal}..."
echo
gh workflow run release.yaml -f version=${NEXT_VERSION}
echo
echo "${bold}Waiting for release to start...${normal}"
sleep 10
set +e
echo "${bold}Head to the release workflow to monitor the release:${normal} $(gh run list --workflow=release.yaml --limit=1 --json url --jq '.[].url')"
id=$(gh run list --workflow=release.yaml --limit=1 --json databaseId --jq '.[].databaseId')
gh run watch $id --exit-status || (echo ; echo "${bold}Logs of failed step:${normal}" && GH_PAGER="" gh run view $id --log-failed)
+58
View File
@@ -0,0 +1,58 @@
name: "Benchmark testing"
on:
workflow_dispatch:
pull_request:
jobs:
Benchmark-Test:
name: "Benchmark tests"
runs-on: ubuntu-20.04
# note: we want benchmarks to run on pull_request events in order to publish results to a sticky comment, and
# we also want to run on push such that merges to main are recorded to the cache. For this reason we don't filter
# the job by event.
steps:
- uses: actions/checkout@v3
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
- name: Restore base benchmark result
uses: actions/cache@v3
with:
path: test/results/benchmark-main.txt
# use base sha for PR or new commit hash for main push in benchmark result key
key: ${{ runner.os }}-bench-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }}
- name: Run benchmark tests
id: benchmark
run: |
REF_NAME=${GITHUB_REF##*/} make benchmark
OUTPUT=$(make show-benchstat)
OUTPUT="${OUTPUT//'%'/'%25'}" # URL encode all '%' characters
OUTPUT="${OUTPUT//$'\n'/'%0A'}" # URL encode all '\n' characters
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
echo "result=$OUTPUT" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v3
with:
name: benchmark-test-results
path: test/results/**/*
- name: Update PR benchmark results comment
uses: marocchino/sticky-pull-request-comment@v2
continue-on-error: true
with:
header: benchmark
message: |
### Benchmark Test Results
<details>
<summary>Benchmark results from the latest changes vs base branch</summary>
```
${{ steps.benchmark.outputs.result }}
```
</details>
+4 -4
View File
@@ -30,11 +30,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -45,7 +45,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -59,4 +59,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
+39 -47
View File
@@ -1,32 +1,29 @@
name: "Release"
on:
push:
# take no actions on push to any branch...
branches-ignore:
- "**"
# ... only act on release tags
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: tag the latest commit on main with the given version (prefixed with v)
required: true
env:
GO_VERSION: "1.18.x"
GO_VERSION: "1.19.x"
jobs:
quality-gate:
environment: release
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
# we don't want to release commits that have been pushed and tagged, but not necessarily merged onto main
- name: Ensure tagged commit is on main
- name: Check if tag already exists
# note: this will fail if the tag already exists
run: |
echo "Tag: ${GITHUB_REF##*/}"
git fetch origin main
git merge-base --is-ancestor ${GITHUB_REF##*/} origin/main && echo "${GITHUB_REF##*/} is a commit on main!"
[[ "${{ github.event.inputs.version }}" == v* ]] || (echo "version '${{ github.event.inputs.version }}' does not have a 'v' prefix" && exit 1)
git tag ${{ github.event.inputs.version }}
- name: Check static analysis results
uses: fountainhead/action-wait-for-check@v1.0.0
uses: fountainhead/action-wait-for-check@v1.1.0
id: static-analysis
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -35,7 +32,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check unit test results
uses: fountainhead/action-wait-for-check@v1.0.0
uses: fountainhead/action-wait-for-check@v1.1.0
id: unit
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -44,7 +41,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check integration test results
uses: fountainhead/action-wait-for-check@v1.0.0
uses: fountainhead/action-wait-for-check@v1.1.0
id: integration
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -53,7 +50,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check acceptance test results (linux)
uses: fountainhead/action-wait-for-check@v1.0.0
uses: fountainhead/action-wait-for-check@v1.1.0
id: acceptance-linux
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -62,7 +59,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check acceptance test results (mac)
uses: fountainhead/action-wait-for-check@v1.0.0
uses: fountainhead/action-wait-for-check@v1.1.0
id: acceptance-mac
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -71,7 +68,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check cli test results (linux)
uses: fountainhead/action-wait-for-check@v1.0.0
uses: fountainhead/action-wait-for-check@v1.1.0
id: cli-linux
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -97,33 +94,15 @@ jobs:
contents: write
packages: write
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
# use the same cache we used for building snapshots
build-cache-key-prefix: "snapshot"
- name: Login to Docker Hub
uses: docker/login-action@v2
@@ -138,16 +117,29 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build & publish release artifacts
run: make release
- name: Tag release
run: |
git tag ${{ github.event.inputs.version }}
git push origin --tags
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build & publish release artifacts
run: make ci-release
env:
# for mac signing and notarization...
QUILL_SIGN_P12: ${{ secrets.ANCHORE_APPLE_DEVELOPER_ID_CERT_CHAIN }}
QUILL_SIGN_PASSWORD: ${{ secrets.ANCHORE_APPLE_DEVELOPER_ID_CERT_PASS }}
QUILL_NOTARY_ISSUER: ${{ secrets.APPLE_NOTARY_ISSUER }}
QUILL_NOTARY_KEY_ID: ${{ secrets.APPLE_NOTARY_KEY_ID }}
QUILL_NOTARY_KEY: ${{ secrets.APPLE_NOTARY_KEY }}
# for creating the release (requires write access to packages and content)
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# for updating brew formula in anchore/homebrew-syft
GITHUB_BREW_TOKEN: ${{ secrets.ANCHORE_GIT_READ_TOKEN }}
# for updating the VERSION file in S3...
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
- uses: anchore/sbom-action@v0
continue-on-error: true
@@ -159,12 +151,12 @@ jobs:
with:
status: ${{ job.status }}
fields: repo,workflow,action,eventName
text: "A new Syft release has been published: https://github.com/anchore/syft/releases/tag/${{ github.ref_name }}"
text: "A new Syft release has been published: https://github.com/anchore/syft/releases/tag/${{ github.event.inputs.version }}"
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
if: ${{ success() }}
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
with:
name: artifacts
path: dist/**/*
+23 -23
View File
@@ -6,7 +6,7 @@ on:
workflow_dispatch:
env:
GO_VERSION: "1.18.x"
GO_VERSION: "1.19.x"
GO_STABLE_VERSION: true
jobs:
@@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
@@ -29,28 +29,27 @@ jobs:
GOSIMPORTS_LATEST_VERSION=$(go list -m -json github.com/rinchsan/gosimports@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')
GLOW_LATEST_VERSION=$(go list -m -json github.com/charmbracelet/glow@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/^(GOSIMPORTS_VERSION = ).*/\1'${GOSIMPORTS_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
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/^(GOSIMPORTS_VERSION := ).*/\1'${GOSIMPORTS_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
sed -r -i -e 's/^(GLOW_VERSION := ).*/\1'${GLOW_LATEST_VERSION}'/' Makefile
# 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=GOSIMPORTS::$GOSIMPORTS_LATEST_VERSION"
echo "::set-output name=YAJSV::$YAJSV_LATEST_VERSION"
echo "::set-output name=COSIGN::$COSIGN_LATEST_VERSION"
echo "GOLANGCILINT=$GOLANGCILINT_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "BOUNCER=$BOUNCER_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "CHRONICLE=$CHRONICLE_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "GORELEASER=$GORELEASER_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "GOSIMPORTS=$GOSIMPORTS_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "YAJSV=$YAJSV_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "COSIGN=$COSIGN_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "GLOW=GLOW_LATEST_VERSION" >> $GITHUB_OUTPUT
id: latest-versions
- uses: tibdex/github-app-token@v1
@@ -65,8 +64,8 @@ jobs:
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.'
commit-message: 'chore(deps): update bootstrap tools to latest versions'
title: 'chore(deps): update 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 }})
@@ -75,5 +74,6 @@ jobs:
- [gosimports ${{ steps.latest-versions.outputs.GOSIMPORTS }}](https://github.com/rinchsan/gosimports/releases/tag/${{ steps.latest-versions.outputs.GOSIMPORTS }})
- [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 }})
- [glow ${{ steps.latest-versions.outputs.GLOW }}](https://github.com/charmbracelet/glow/releases/tag/${{ steps.latest-versions.outputs.GLOW }})
This is an auto-generated pull request to update all of the bootstrap tools to the latest versions.
token: ${{ steps.generate-token.outputs.token }}
token: ${{ steps.generate-token.outputs.token }}
@@ -6,7 +6,7 @@ on:
workflow_dispatch:
env:
GO_VERSION: "1.18.x"
GO_VERSION: "1.19.x"
GO_STABLE_VERSION: true
jobs:
@@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
@@ -29,7 +29,7 @@ jobs:
go mod tidy
# export the version for use with create-pull-request
echo "::set-output name=LATEST_VERSION::$LATEST_VERSION"
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_OUTPUT
id: latest-version
- uses: tibdex/github-app-token@v1
@@ -42,10 +42,10 @@ jobs:
with:
signoff: true
delete-branch: true
branch: auto/latest
branch: auto/latest-stereoscope
labels: dependencies
commit-message: "Update Stereoscope to ${{ steps.latest-version.outputs.LATEST_VERSION }}"
title: "Update Stereoscope to ${{ steps.latest-version.outputs.LATEST_VERSION }}"
commit-message: "chore(deps): update stereoscope to ${{ steps.latest-version.outputs.LATEST_VERSION }}"
title: "chore(deps): update stereoscope to ${{ steps.latest-version.outputs.LATEST_VERSION }}"
body: |
Update Stereoscope to ${{ steps.latest-version.outputs.LATEST_VERSION }}
token: ${{ steps.generate-token.outputs.token }}
+61 -259
View File
@@ -1,14 +1,11 @@
name: "Validations"
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
pull_request:
env:
GO_VERSION: "1.18.x"
GO_STABLE_VERSION: true
jobs:
@@ -17,155 +14,72 @@ jobs:
name: "Static analysis"
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Bootstrap CI environment dependencies
run: make ci-bootstrap
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
- name: Run static analysis
run: make static-analysis
Unit-Test:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "Unit tests"
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Bootstrap CI environment dependencies
run: make ci-bootstrap
- name: Build cache key for java test-fixture blobs (for unit tests)
run: make java-packages-fingerprint
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
- name: Restore Java test-fixture cache
id: unit-java-cache
uses: actions/cache@v2.1.3
uses: actions/cache@v3
with:
path: syft/pkg/cataloger/java/test-fixtures/java-builds/packages
key: ${{ runner.os }}-unit-java-cache-${{ hashFiles( 'syft/pkg/cataloger/java/test-fixtures/java-builds/packages.fingerprint' ) }}
- name: Build cache key for rpm test-fixture blobs (for unit tests)
run: make rpm-binaries-fingerprint
- name: Restore RPM test-fixture cache
id: unit-rpm-cache
uses: actions/cache@v2.1.3
uses: actions/cache@v3
with:
path: syft/pkg/cataloger/rpm/test-fixtures/rpms
key: ${{ runner.os }}-unit-rpm-cache-${{ hashFiles( 'syft/pkg/cataloger/rpm/test-fixtures/rpms.fingerprint' ) }}
- name: Build cache key for go binary test-fixture blobs (for unit tests)
run: make go-binaries-fingerprint
- name: Restore Go binary test-fixture cache
- name: Restore go binary test-fixture cache
id: unit-go-binary-cache
uses: actions/cache@v2.1.3
uses: actions/cache@v3
with:
path: syft/pkg/cataloger/golang/test-fixtures/archs/binaries
key: ${{ runner.os }}-unit-go-binaries-cache-${{ hashFiles( 'syft/pkg/cataloger/golang/test-fixtures/archs/binaries.fingerprint' ) }}
- name: Restore binary cataloger test-fixture cache
id: unit-binary-cataloger-cache
uses: actions/cache@v3
with:
path: syft/pkg/cataloger/binary/test-fixtures/classifiers/dynamic
key: ${{ runner.os }}-unit-binary-cataloger-cache-${{ hashFiles( 'syft/pkg/cataloger/binary/test-fixtures/cache.fingerprint' ) }}
- name: Run unit tests
run: make unit
- uses: actions/upload-artifact@v2
with:
name: unit-test-results
path: test/results/**/*
Integration-Test:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "Integration tests"
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Bootstrap CI environment dependencies
run: make ci-bootstrap
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
- name: Validate syft output against the CycloneDX schema
run: make validate-cyclonedx-schema
- name: Build key for tar cache
run: make integration-fingerprint
- name: Restore integration test cache
uses: actions/cache@v2.1.3
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/test/integration/test-fixtures/cache
key: ${{ runner.os }}-integration-test-cache-${{ hashFiles('test/integration/test-fixtures/cache.fingerprint') }}
@@ -173,123 +87,35 @@ jobs:
- name: Run integration tests
run: make integration
Benchmark-Test:
name: "Benchmark tests"
runs-on: ubuntu-20.04
# note: we want benchmarks to run on pull_request events in order to publish results to a sticky comment, and
# we also want to run on push such that merges to main are recorded to the cache. For this reason we don't filter
# the job by event.
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
- uses: actions/checkout@v2
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Bootstrap CI environment dependencies
run: make ci-bootstrap
- name: Restore base benchmark result
uses: actions/cache@v2
with:
path: test/results/benchmark-main.txt
# use base sha for PR or new commit hash for main push in benchmark result key
key: ${{ runner.os }}-bench-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }}
- name: Run benchmark tests
id: benchmark
run: |
REF_NAME=${GITHUB_REF##*/} make benchmark
OUTPUT=$(make show-benchstat)
OUTPUT="${OUTPUT//'%'/'%25'}" # URL encode all '%' characters
OUTPUT="${OUTPUT//$'\n'/'%0A'}" # URL encode all '\n' characters
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
echo "::set-output name=result::$OUTPUT"
- uses: actions/upload-artifact@v2
with:
name: benchmark-test-results
path: test/results/**/*
- name: Update PR benchmark results comment
uses: marocchino/sticky-pull-request-comment@v2
continue-on-error: true
with:
header: benchmark
message: |
### Benchmark Test Results
<details>
<summary>Benchmark results from the latest changes vs base branch</summary>
```
${{ steps.benchmark.outputs.result }}
```
</details>
Build-Snapshot-Artifacts:
name: "Build snapshot artifacts"
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
- uses: actions/checkout@v3
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
# why have another build cache key? We don't want unit/integration/etc test build caches to replace
# the snapshot build cache, which includes builds for all OSs and architectures. As long as this key is
# unique from the build-cache-key-prefix in other CI jobs, we should be fine.
#
# note: ideally this value should match what is used in release (just to help with build times).
build-cache-key-prefix: "snapshot"
bootstrap-apt-packages: ""
- name: Build snapshot artifacts
run: make snapshot
- uses: actions/upload-artifact@v2
# why not use actions/upload-artifact? It is very slow (3 minutes to upload ~600MB of data, vs 10 seconds with this approach).
# see https://github.com/actions/upload-artifact/issues/199 for more info
- name: Upload snapshot artifacts
uses: actions/cache/save@v3
with:
name: artifacts
path: snapshot/**/*
path: snapshot
key: snapshot-build-${{ github.run_id }}
Acceptance-Linux:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
@@ -297,22 +123,20 @@ jobs:
needs: [Build-Snapshot-Artifacts]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
- name: Download snapshot build
uses: actions/cache/restore@v3
with:
name: artifacts
path: snapshot
key: snapshot-build-${{ github.run_id }}
- name: Run comparison tests (Linux)
run: make compare-linux
- name: Build key for image cache
run: make install-fingerprint
- name: Restore install.sh test image cache
id: install-test-image-cache
uses: actions/cache@v2.1.3
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/test/install/cache
key: ${{ runner.os }}-install-test-image-cache-${{ hashFiles('test/install/cache.fingerprint') }}
@@ -335,16 +159,17 @@ jobs:
needs: [Build-Snapshot-Artifacts]
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
- name: Download snapshot build
uses: actions/cache/restore@v3
with:
name: artifacts
path: snapshot
key: snapshot-build-${{ github.run_id }}
- name: Restore docker image cache for compare testing
id: mac-compare-testing-cache
uses: actions/cache@v2.1.3
uses: actions/cache@v3
with:
path: image.tar
key: ${{ runner.os }}-${{ hashFiles('test/compare/mac.sh') }}
@@ -355,52 +180,29 @@ jobs:
- name: Run install.sh tests (Mac)
run: make install-test-ci-mac
Cli-Linux:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "CLI tests (Linux)"
needs: [Build-Snapshot-Artifacts]
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Build key for tar cache
run: make cli-fingerprint
- name: Restore CLI test cache
uses: actions/cache@v2.1.3
- name: Restore CLI test-fixture cache
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/test/cli/test-fixtures/cache
key: ${{ runner.os }}-cli-test-cache-${{ hashFiles('test/cli/test-fixtures/cache.fingerprint') }}
- uses: actions/download-artifact@v2
- name: Download snapshot build
uses: actions/cache/restore@v3
with:
name: artifacts
path: snapshot
key: snapshot-build-${{ github.run_id }}
- name: Run CLI Tests (Linux)
run: make cli
+1
View File
@@ -1,4 +1,5 @@
CHANGELOG.md
VERSION
/test/results
/dist
/snapshot
+30 -6
View File
@@ -1,5 +1,7 @@
# TODO: enable this when we have coverage on docstring comments
#issues:
issues:
max-same-issues: 25
# TODO: enable this when we have coverage on docstring comments
# # The list of ids of default excludes to include or disable.
# include:
# - EXC0002 # disable excluding of issues about comments from golint
@@ -21,6 +23,7 @@ linters:
- gocritic
- gocyclo
- gofmt
- goimports
- goprintffuncname
- gosec
- gosimple
@@ -28,7 +31,6 @@ linters:
- ineffassign
- misspell
- nakedret
- nolintlint
- revive
- staticcheck
- stylecheck
@@ -38,7 +40,25 @@ linters:
- unused
- whitespace
linters-settings:
funlen:
# Checks the number of lines in a function.
# If lower than 0, disable the check.
# Default: 60
lines: 70
# Checks the number of statements in a function.
# If lower than 0, disable the check.
# Default: 40
statements: 50
output:
uniq-by-line: false
run:
timeout: 10m
# do not enable...
# - deadcode # The owner seems to have abandoned the linter. Replaced by "unused".
# - goprintffuncname # does not catch all cases and there are exceptions
# - nakedret # does not catch all cases and should not fail a build
# - gochecknoglobals
# - gochecknoinits # this is too aggressive
# - rowserrcheck disabled per generics https://github.com/golangci/golangci-lint/issues/2649
@@ -52,7 +72,11 @@ linters:
# - lll # without a way to specify per-line exception cases, this is not usable
# - maligned # this is an excellent linter, but tricky to optimize and we are not sensitive to memory layout optimizations
# - nestif
# - prealloc # following this rule isn't consistently a good idea, as it sometimes forces unnecessary allocations that result in less idiomatic code
# - scopelint # deprecated
# - nolintlint # as of go1.19 this conflicts with the behavior of gofmt, which is a deal-breaker (lint-fix will still fail when running lint)
# - prealloc # following this rule isn't consistently a good idea, as it sometimes forces unnecessary allocations that result in less idiomatic code
# - rowserrcheck # not in a repo with sql, so this is not useful
# - scopelint # deprecated
# - structcheck # The owner seems to have abandoned the linter. Replaced by "unused".
# - testpackage
# - wsl # this doens't have an auto-fixer yet and is pretty noisy (https://github.com/bombsimon/wsl/issues/90)
# - varcheck # The owner seems to have abandoned the linter. Replaced by "unused".
# - wsl # this doens't have an auto-fixer yet and is pretty noisy (https://github.com/bombsimon/wsl/issues/90)
+1 -4
View File
@@ -5,6 +5,7 @@ release:
env:
# required to support multi architecture docker builds
- DOCKER_CLI_EXPERIMENTAL=enabled
- CGO_ENABLED=0
builds:
- id: linux-build
@@ -19,8 +20,6 @@ builds:
- s390x
# set the modified timestamp on the output binary to the git timestamp to ensure a reproducible build
mod_timestamp: &build-timestamp '{{ .CommitTimestamp }}'
env: &build-env
- CGO_ENABLED=0
ldflags: &build-ldflags |
-w
-s
@@ -39,7 +38,6 @@ builds:
- amd64
- arm64
mod_timestamp: *build-timestamp
env: *build-env
ldflags: *build-ldflags
hooks:
post:
@@ -55,7 +53,6 @@ builds:
goarch:
- amd64
mod_timestamp: *build-timestamp
env: *build-env
ldflags: *build-ldflags
archives:
+2 -2
View File
@@ -1,4 +1,4 @@
# Contributing to Syft
[#](#) Contributing to Syft
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.
@@ -10,7 +10,7 @@ Before you can contribute to Syft, you need to configure your development enviro
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.
Refer to the go.mod file in the root of this repo for the recommended version of Go to install.
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/).
+7
View File
@@ -0,0 +1,7 @@
# Syft Contributors
The following Syft components were contributed by external authors/organizations.
## GraalVM Native Image
A cataloger contributed by Oracle Corporation that extracts packages given within GraalVM Native Image SBOMs.
+74 -40
View File
@@ -15,37 +15,16 @@ After cloning the following step can help you get setup:
- this command `go run cmd/syft/main.go alpine:latest` will compile and run syft against `alpine:latest`
5. view the README or syft help output for more output options
#### Make output
The main make tasks for common static analysis and testing are `lint`, `lint-fix`, `unit`, `integration`, and `cli`.
```
all Run all linux-based checks (linting, license check, unit, integration, and linux compare tests)
benchmark Run benchmark tests and compare against the baseline (if available)
bootstrap Download and install all tooling dependencies (+ prep tooling in the ./tmp dir)
build Build release snapshot binaries and packages
check-licenses Ensure transitive dependencies are compliant with the current license policy
clean-test-image-cache Clean test image cache
clean Remove previous builds, result reports, and test cache
cli Run CLI tests
compare-linux Run compare tests on build snapshot binaries and packages (Linux)
compare-mac Run compare tests on build snapshot binaries and packages (Mac)
generate-json-schema Generate a new json schema
generate-license-list Generate an updated spdx license list
help Display this help
integration Run integration tests
lint-fix Auto-format all source code + run golangci lint fixers
lint Run gofmt + golangci lint checks
show-test-image-cache Show all docker and image tar cache
show-test-snapshots Show all test snapshots
snapshot-with-signing Build snapshot release binaries and packages (with dummy signing)
test Run all tests (currently unit, integration, linux compare, and cli tests)
unit Run unit tests (with coverage)
```
See `make help` for all the current make tasks.
## Architecture
Syft is used to generate a Software Bill of Materials (SBOM) from different kinds of input.
### Code organization for the cmd package
Syft's entrypoint can be found in the `cmd` package at `cmd/syft/main.go`. `main.go` builds a new syft `cli` via `cli.New()`
and then executes the `cli` via `cli.Execute()`. The `cli` package is responsible for parsing command line arguments,
setting up the application context and configuration, and executing the application. Each of syft's commands
@@ -55,23 +34,24 @@ They are registered in `syft/cli/commands/go`.
.
└── syft/
├── cli/
│   ├── attest/
│   ├── attest.go
│   ├── commands.go
│   ├── completion.go
│   ├── convert/
│   ├── convert.go
│   ├── eventloop/
│   ├── options/
│   ├── packages/
│   ├── packages.go
│   ├── poweruser/
│   ├── poweruser.go
│   └── version.go
│ ├── attest/
│ ├── attest.go
│ ├── commands.go
│ ├── completion.go
│ ├── convert/
│ ├── convert.go
│ ├── eventloop/
│ ├── options/
│ ├── packages/
│ ├── packages.go
│ ├── poweruser/
│ ├── poweruser.go
│ └── version.go
└── main.go
```
#### Execution flow
```mermaid
sequenceDiagram
participant main as cmd/syft/main
@@ -100,19 +80,19 @@ sequenceDiagram
Syft's core library (see, exported) functionality is implemented in the `syft` package. The `syft` package is responsible for organizing the core
SBOM data model, it's translated output formats, and the core SBOM generation logic.
#### Organization and design notes for the syft library
- analysis creates a static SBOM which can be encoded and decoded
- format objects, should strive to not add or enrich data in encoding that could otherwise be done during analysis
- package catalogers and their organization can be viewed/added to the `syft/pkg/cataloger` package
- file catalogers and their organization can be viewed/added to the `syft/file` package
- The source package provides an abstraction to allow a user to loosely define a data source that can be cataloged
- Logging Abstraction ...
#### Code example of syft as a library
Here is a gist of using syft as a library to generate a SBOM from a docker image: [link](https://gist.github.com/wagoodman/57ed59a6d57600c23913071b8470175b).
Here is a gist of using syft as a library to generate a SBOM for a docker image: [link](https://gist.github.com/wagoodman/57ed59a6d57600c23913071b8470175b).
The execution flow for the example is detailed below.
#### Execution flow examples for the syft library
```mermaid
sequenceDiagram
participant source as source.New(ubuntu:latest)
@@ -132,6 +112,60 @@ sequenceDiagram
```
### Syft Catalogers
##### Summary
Catalogers are the way in which syft is able to identify and construct packages given some amount of source metadata.
For example, Syft can locate and process `package-lock.json` files when performing filesystem scans.
See: [how to specify file globs](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/javascript/cataloger.go#L16-L21)
and an implementation of the [package-lock.json parser](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/javascript/cataloger.go#L16-L21) fora quick review.
#### Building a new Cataloger
Catalogers must fulfill the interface [found here](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger.go).
This means that when building a new cataloger, the new struct must implement both method signatures of `Catalog` and `Name`.
A top level view of the functions that construct all the catalogers can be found [here](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/cataloger.go).
When an author has finished writing a new cataloger this is the spot to plug in the new catalog constructor.
For a top level view of how the catalogers are used see [this function](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/catalog.go#L41-L100) as a reference. It ranges over all catalogers passed as an argument and invokes the `Catalog` method:
Each cataloger has its own `Catalog` method, but this does not mean that they are all vastly different.
Take a look at the `apkdb` cataloger for alpine to see how it [constructs a generic.NewCataloger](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/apkdb/cataloger.go).
`generic.NewCataloger` is an abstraction syft uses to make writing common components easier. First, it takes the `catalogerName` to identify the cataloger.
On the other side of the call it uses two key pieces which inform the cataloger how to identify and return packages, the `globPatterns` and the `parseFunction`:
- The first piece is a `parseByGlob` matching pattern used to identify the files that contain the package metadata.
See [here for the APK example](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/apk_metadata.go#L16-L41).
- The other is a `parseFunction` which informs the cataloger what to do when it has found one of the above matches files.
See this [link for an example](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/apkdb/parse_apk_db.go#L22-L102).
If you're unsure about using the `Generic Cataloger` and think the use case being filled requires something more custom
just file an issue or ask in our slack, and we'd be more than happy to help on the design.
Identified packages share a common struct so be sure that when the new cataloger is constructing a new package it is using the [`Package` struct](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/package.go#L16-L31).
Metadata Note: Identified packages are also assigned specific metadata that can be unique to their environment.
See [this folder](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg) for examples of the different metadata types.
These are plugged into the `MetadataType` and `Metadata` fields in the above struct. `MetadataType` informs which type is being used. `Metadata` is an interface converted to that type.
Finally, here is an example of where the package construction is done in the apk cataloger. The first link is where `newPackage` is called in the `parseFunction`. The second link shows the package construction:
- [Call for new package](https://github.com/anchore/syft/blob/v0.70.0/syft/pkg/cataloger/apkdb/parse_apk_db.go#L106)
- [APK Package Constructor](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/apkdb/package.go#L12-L27)
If you have more questions about implementing a cataloger or questions about one you might be currently working
always feel free to file an issue or reach out to us [on slack](https://anchore.com/slack).
#### Searching for files
All catalogers are provided an instance of the [`source.FileResolver`](https://github.com/anchore/syft/blob/v0.70.0/syft/source/file_resolver.go#L8) to interface with the image and search for files. The implementations for these
abstractions leverage [`stereoscope`](https://github.com/anchore/stereoscope) in order to perform searching. Here is a
rough outline how that works:
1. a stereoscope `file.Index` is searched based on the input given (a path, glob, or MIME type). The index is relatively fast to search, but requires results to be filtered down to the files that exist in the specific layer(s) of interest. This is done automatically by the `filetree.Searcher` abstraction. This abstraction will fallback to searching directly against the raw `filetree.FileTree` if the index does not contain the file(s) of interest. Note: the `filetree.Searcher` is used by the `source.FileResolver` abstraction.
2. Once the set of files are returned from the `filetree.Searcher` the results are filtered down further to return the most unique file results. For example, you may have requested for files by a glob that returns multiple results. These results are filtered down to deduplicate by real files, so if a result contains two references to the same file, say one accessed via symlink and one accessed via the real path, then the real path reference is returned and the symlink reference is filtered out. If both were accessed by symlink then the first (by lexical order) is returned. This is done automatically by the `source.FileResolver` abstraction.
3. By the time results reach the `pkg.Cataloger` you are guaranteed to have a set of unique files that exist in the layer(s) of interest (relative to what the resolver supports).
## Testing
+270 -291
View File
@@ -1,24 +1,26 @@
BIN = syft
VERSION=$(shell git describe --dirty --always --tags)
TEMPDIR = ./.tmp
BIN := syft
TEMP_DIR := ./.tmp
# commands and versions
LINTCMD = $(TEMPDIR)/golangci-lint run --tests=false --timeout=5m --config .golangci.yaml
GOIMPORTS_CMD = $(TEMPDIR)/gosimports -local github.com/anchore
RELEASE_CMD=$(TEMPDIR)/goreleaser release --rm-dist
SNAPSHOT_CMD=$(RELEASE_CMD) --skip-publish --snapshot
# Command templates #################################
LINT_CMD := $(TEMP_DIR)/golangci-lint run --tests=false
GOIMPORTS_CMD := $(TEMP_DIR)/gosimports -local github.com/anchore
RELEASE_CMD := $(TEMP_DIR)/goreleaser release --clean
SNAPSHOT_CMD := $(RELEASE_CMD) --skip-publish --skip-sign --snapshot
CHRONICLE_CMD = $(TEMP_DIR)/chronicle
GLOW_CMD = $(TEMP_DIR)/glow
# tool versions
GOLANGCILINT_VERSION = v1.50.1
GOSIMPORTS_VERSION = v0.3.4
BOUNCER_VERSION = v0.4.0
CHRONICLE_VERSION = v0.4.2
GORELEASER_VERSION = v1.12.3
YAJSV_VERSION = v1.4.1
COSIGN_VERSION = v1.13.1
QUILL_VERSION = v0.2.0
# Tool versions #################################
GOLANGCILINT_VERSION := v1.52.2
GOSIMPORTS_VERSION := v0.3.8
BOUNCER_VERSION := v0.4.0
CHRONICLE_VERSION := v0.6.0
GORELEASER_VERSION := v1.16.2
YAJSV_VERSION := v1.4.1
COSIGN_VERSION := v1.13.1
QUILL_VERSION := v0.2.0
GLOW_VERSION := v1.5.0
# formatting variables
# Formatting variables #################################
BOLD := $(shell tput -T linux bold)
PURPLE := $(shell tput -T linux setaf 5)
GREEN := $(shell tput -T linux setaf 2)
@@ -28,55 +30,23 @@ RESET := $(shell tput -T linux sgr0)
TITLE := $(BOLD)$(PURPLE)
SUCCESS := $(BOLD)$(GREEN)
# test variables
RESULTSDIR = test/results
COMPARE_DIR = ./test/compare
COMPARE_TEST_IMAGE = centos:8.2.2004
COVER_REPORT = $(RESULTSDIR)/unit-coverage-details.txt
COVER_TOTAL = $(RESULTSDIR)/unit-coverage-summary.txt
# the quality gate lower threshold for unit test total % coverage (by function statements)
COVERAGE_THRESHOLD := 62
# Test variables #################################
COMPARE_DIR := ./test/compare
COMPARE_TEST_IMAGE := centos:8.2.2004
COVERAGE_THRESHOLD := 62 # the quality gate lower threshold for unit test total % coverage (by function statements)
# CI cache busting values; change these if you want CI to not use previous stored cache
INTEGRATION_CACHE_BUSTER="894d8ca"
CLI_CACHE_BUSTER="e5cdfd8"
BOOTSTRAP_CACHE="c7afb99ad"
## Build variables
DISTDIR=./dist
SNAPSHOTDIR=./snapshot
OS=$(shell uname | tr '[:upper:]' '[:lower:]')
SNAPSHOT_BIN=$(realpath $(shell pwd)/$(SNAPSHOTDIR)/$(OS)-build_$(OS)_amd64_v1/$(BIN))
## Variable assertions
ifndef TEMPDIR
$(error TEMPDIR is not set)
endif
ifndef RESULTSDIR
$(error RESULTSDIR is not set)
endif
ifndef COMPARE_DIR
$(error COMPARE_DIR is not set)
endif
ifndef DISTDIR
$(error DISTDIR is not set)
endif
ifndef SNAPSHOTDIR
$(error SNAPSHOTDIR is not set)
endif
## Build variables #################################
VERSION := $(shell git describe --dirty --always --tags)
DIST_DIR := ./dist
SNAPSHOT_DIR := ./snapshot
CHANGELOG := CHANGELOG.md
OS := $(shell uname | tr '[:upper:]' '[:lower:]')
SNAPSHOT_BIN := $(realpath $(shell pwd)/$(SNAPSHOT_DIR)/$(OS)-build_$(OS)_amd64_v1/$(BIN))
ifndef VERSION
$(error VERSION is not set)
endif
ifndef REF_NAME
REF_NAME = $(VERSION)
endif
define title
@printf '$(TITLE)$(1)$(RESET)\n'
endef
@@ -89,65 +59,59 @@ define safe_rm_rf_children
bash -c 'test -z "$(1)" && false || rm -rf $(1)/*'
endef
## Default Task
.DEFAULT_GOAL:=help
## Tasks
.PHONY: all
all: clean static-analysis test ## Run all linux-based checks (linting, license check, unit, integration, and linux compare tests)
all: static-analysis test ## Run all linux-based checks (linting, license check, unit, integration, and linux compare tests)
@printf '$(SUCCESS)All checks pass!$(RESET)\n'
.PHONY: static-analysis
static-analysis: check-go-mod-tidy lint check-licenses check-json-schema-drift ## Run all static analysis checks
.PHONY: test
test: unit validate-cyclonedx-schema integration benchmark compare-linux cli ## Run all tests (currently unit, integration, linux compare, and cli tests)
test: unit integration validate-cyclonedx-schema benchmark cli ## Run all tests (currently unit, integration, linux compare, and cli tests)
.PHONY: ci-bootstrap
ci-bootstrap:
DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y bc jq libxml2-utils
.PHONY:
ci-bootstrap-mac:
github_changelog_generator --version || sudo gem install github_changelog_generator
## Bootstrapping targets #################################
$(RESULTSDIR):
mkdir -p $(RESULTSDIR)
$(TEMPDIR):
mkdir -p $(TEMPDIR)
.PHONY: bootstrap
bootstrap: $(TEMP_DIR) bootstrap-go bootstrap-tools ## Download and install all tooling dependencies (+ prep tooling in the ./tmp dir)
$(call title,Bootstrapping dependencies)
.PHONY: bootstrap-tools
bootstrap-tools: $(TEMPDIR)
curl -sSfL https://raw.githubusercontent.com/anchore/quill/main/install.sh | sh -s -- -b $(TEMPDIR)/ $(QUILL_VERSION)
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)
bootstrap-tools: $(TEMP_DIR)
curl -sSfL https://raw.githubusercontent.com/anchore/quill/main/install.sh | sh -s -- -b $(TEMP_DIR)/ $(QUILL_VERSION)
GO111MODULE=off GOBIN=$(realpath $(TEMP_DIR)) go get -u golang.org/x/perf/cmd/benchstat
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMP_DIR)/ $(GOLANGCILINT_VERSION)
curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMP_DIR)/ $(BOUNCER_VERSION)
curl -sSfL https://raw.githubusercontent.com/anchore/chronicle/main/install.sh | sh -s -- -b $(TEMP_DIR)/ $(CHRONICLE_VERSION)
.github/scripts/goreleaser-install.sh -d -b $(TEMP_DIR)/ $(GORELEASER_VERSION)
# the only difference between goimports and gosimports is that gosimports removes extra whitespace between import blocks (see https://github.com/golang/go/issues/20818)
GOBIN="$(realpath $(TEMPDIR))" go install github.com/rinchsan/gosimports/cmd/gosimports@$(GOSIMPORTS_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)
GOBIN="$(realpath $(TEMP_DIR))" go install github.com/rinchsan/gosimports/cmd/gosimports@$(GOSIMPORTS_VERSION)
GOBIN="$(realpath $(TEMP_DIR))" go install github.com/neilpa/yajsv@$(YAJSV_VERSION)
GOBIN="$(realpath $(TEMP_DIR))" go install github.com/sigstore/cosign/cmd/cosign@$(COSIGN_VERSION)
GOBIN="$(realpath $(TEMP_DIR))" go install github.com/charmbracelet/glow@$(GLOW_VERSION)
.PHONY: bootstrap-go
bootstrap-go:
go mod download
.PHONY: bootstrap
bootstrap: $(RESULTSDIR) bootstrap-go bootstrap-tools ## Download and install all tooling dependencies (+ prep tooling in the ./tmp dir)
$(call title,Bootstrapping dependencies)
$(TEMP_DIR):
mkdir -p $(TEMP_DIR)
.PHONY: static-analysis
static-analysis: check-go-mod-tidy check-licenses lint
## Static analysis targets #################################
.PHONY: lint
lint: ## Run gofmt + golangci lint checks
lint: ## Run gofmt + golangci lint checks
$(call title,Running linters)
# ensure there are no go fmt differences
@printf "files with gofmt issues: [$(shell gofmt -l -s .)]\n"
@test -z "$(shell gofmt -l -s .)"
# run all golangci-lint rules
$(LINTCMD)
$(LINT_CMD)
@[ -z "$(shell $(GOIMPORTS_CMD) -d .)" ] || (echo "goimports needs to be fixed" && false)
# go tooling does not play well with certain filename characters, ensure the common cases don't result in future "go get" failures
@@ -155,243 +119,109 @@ lint: ## Run gofmt + golangci lint checks
@bash -c "[[ '$(MALFORMED_FILENAMES)' == '' ]] || (printf '\nfound unsupported filename characters:\n$(MALFORMED_FILENAMES)\n\n' && false)"
.PHONY: lint-fix
lint-fix: ## Auto-format all source code + run golangci lint fixers
lint-fix: ## Auto-format all source code + run golangci lint fixers
$(call title,Running lint fixers)
gofmt -w -s .
$(GOIMPORTS_CMD) -w .
$(LINTCMD) --fix
$(LINT_CMD) --fix
go mod tidy
.PHONY: check-licenses
check-licenses: ## Ensure transitive dependencies are compliant with the current license policy
$(TEMPDIR)/bouncer check ./...
check-licenses: ## Ensure transitive dependencies are compliant with the current license policy
$(call title,Checking for license compliance)
$(TEMP_DIR)/bouncer check ./...
check-go-mod-tidy:
@ .github/scripts/go-mod-tidy-check.sh && echo "go.mod and go.sum are tidy!"
check-json-schema-drift:
$(call title,Ensure there is no drift between the JSON schema and the code)
@.github/scripts/json-schema-drift-check.sh
## Testing targets #################################
.PHONY: unit
unit: $(TEMP_DIR) fixtures ## Run unit tests (with coverage)
$(call title,Running unit tests)
go test -coverprofile $(TEMP_DIR)/unit-coverage-details.txt $(shell go list ./... | grep -v anchore/syft/test)
@.github/scripts/coverage.py $(COVERAGE_THRESHOLD) $(TEMP_DIR)/unit-coverage-details.txt
.PHONY: integration
integration: ## Run integration tests
$(call title,Running integration tests)
go test -v ./test/integration
.PHONY: validate-cyclonedx-schema
validate-cyclonedx-schema:
cd schema/cyclonedx && make
.PHONY: unit
unit: $(RESULTSDIR) fixtures ## Run unit tests (with coverage)
$(call title,Running unit tests)
go test -coverprofile $(COVER_REPORT) $(shell go list ./... | grep -v anchore/syft/test)
@go tool cover -func $(COVER_REPORT) | grep total | awk '{print substr($$3, 1, length($$3)-1)}' > $(COVER_TOTAL)
@echo "Coverage: $$(cat $(COVER_TOTAL))"
@if [ $$(echo "$$(cat $(COVER_TOTAL)) >= $(COVERAGE_THRESHOLD)" | bc -l) -ne 1 ]; then echo "$(RED)$(BOLD)Failed coverage quality gate (> $(COVERAGE_THRESHOLD)%)$(RESET)" && false; fi
.PHONY: cli
cli: $(SNAPSHOT_DIR) ## Run CLI tests
chmod 755 "$(SNAPSHOT_BIN)"
$(SNAPSHOT_BIN) version
SYFT_BINARY_LOCATION='$(SNAPSHOT_BIN)' \
go test -count=1 -timeout=15m -v ./test/cli
## Benchmark test targets #################################
.PHONY: benchmark
benchmark: $(RESULTSDIR) ## Run benchmark tests and compare against the baseline (if available)
benchmark: $(TEMP_DIR) ## Run benchmark tests and compare against the baseline (if available)
$(call title,Running benchmark tests)
go test -p 1 -run=^Benchmark -bench=. -count=5 -benchmem ./... | tee $(RESULTSDIR)/benchmark-$(REF_NAME).txt
(test -s $(RESULTSDIR)/benchmark-main.txt && \
$(TEMPDIR)/benchstat $(RESULTSDIR)/benchmark-main.txt $(RESULTSDIR)/benchmark-$(REF_NAME).txt || \
$(TEMPDIR)/benchstat $(RESULTSDIR)/benchmark-$(REF_NAME).txt) \
| tee $(RESULTSDIR)/benchstat.txt
go test -p 1 -run=^Benchmark -bench=. -count=7 -benchmem ./... | tee $(TEMP_DIR)/benchmark-$(VERSION).txt
(test -s $(TEMP_DIR)/benchmark-main.txt && \
$(TEMP_DIR)/benchstat $(TEMP_DIR)/benchmark-main.txt $(TEMP_DIR)/benchmark-$(VERSION).txt || \
$(TEMP_DIR)/benchstat $(TEMP_DIR)/benchmark-$(VERSION).txt) \
| tee $(TEMP_DIR)/benchstat.txt
.PHONY: show-benchstat
show-benchstat:
@cat $(RESULTSDIR)/benchstat.txt
@cat $(TEMP_DIR)/benchstat.txt
# note: this is used by CI to determine if the install test fixture cache (docker image tars) should be busted
install-fingerprint:
cd test/install && \
## Test-fixture-related targets #################################
# note: this is used by CI to determine if various test fixture cache should be restored or recreated
fingerprints:
$(call title,Creating all test cache input fingerprints)
# for IMAGE integration test fixtures
cd test/integration/test-fixtures && \
make cache.fingerprint
install-test: $(SNAPSHOTDIR)
cd test/install && \
make
# for BINARY test fixtures
cd syft/pkg/cataloger/binary/test-fixtures && \
make cache.fingerprint
install-test-cache-save: $(SNAPSHOTDIR)
cd test/install && \
make save
install-test-cache-load: $(SNAPSHOTDIR)
cd test/install && \
make load
install-test-ci-mac: $(SNAPSHOTDIR)
cd test/install && \
make ci-test-mac
.PHONY: integration
integration: ## Run integration tests
$(call title,Running integration tests)
go test -v ./test/integration
# note: this is used by CI to determine if the integration test fixture cache (docker image tars) should be busted
integration-fingerprint:
$(call title,Integration test fixture fingerprint)
find test/integration/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | tee /dev/stderr | md5sum | tee test/integration/test-fixtures/cache.fingerprint && echo "$(INTEGRATION_CACHE_BUSTER)" >> test/integration/test-fixtures/cache.fingerprint
.PHONY: java-packages-fingerprint
java-packages-fingerprint:
$(call title,Java test fixture fingerprint)
# for JAVA BUILD test fixtures
cd syft/pkg/cataloger/java/test-fixtures/java-builds && \
make packages.fingerprint
.PHONY: go-binaries-fingerprint
go-binaries-fingerprint:
$(call title,Go binaries test fixture fingerprint)
# for GO BINARY test fixtures
cd syft/pkg/cataloger/golang/test-fixtures/archs && \
make binaries.fingerprint
.PHONY: rpm-binaries-fingerprint
rpm-binaries-fingerprint:
$(call title,RPM binary test fixture fingerprint)
# for RPM test fixtures
cd syft/pkg/cataloger/rpm/test-fixtures && \
make rpms.fingerprint
# for INSTALL integration test fixtures
cd test/install && \
make cache.fingerprint
# for CLI test fixtures
cd test/cli/test-fixtures && \
make cache.fingerprint
.PHONY: fixtures
fixtures:
$(call title,Generating test fixtures)
cd syft/pkg/cataloger/java/test-fixtures/java-builds && make
cd syft/pkg/cataloger/rpm/test-fixtures && make
.PHONY: generate-json-schema
generate-json-schema: ## Generate a new json schema
cd schema/json && go run generate.go
.PHONY: generate-license-list
generate-license-list: ## Generate an updated spdx license list
go generate ./internal/spdxlicense/...
gofmt -s -w ./internal/spdxlicense
.PHONY: build
build: $(SNAPSHOTDIR) ## Build release snapshot binaries and packages
$(SNAPSHOTDIR): ## Build snapshot release binaries and packages
$(call title,Building snapshot artifacts)
# create a config with the dist dir overridden
echo "dist: $(SNAPSHOTDIR)" > $(TEMPDIR)/goreleaser.yaml
cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml
# build release snapshots
bash -c "SKIP_SIGNING=true $(SNAPSHOT_CMD) --skip-sign --config $(TEMPDIR)/goreleaser.yaml"
.PHONY: snapshot-with-signing
snapshot-with-signing: ## Build snapshot release binaries and packages (with dummy signing)
$(call title,Building snapshot artifacts (+ signing))
# create a config with the dist dir overridden
echo "dist: $(SNAPSHOTDIR)" > $(TEMPDIR)/goreleaser.yaml
cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml
# build release snapshots
bash -c "\
$(SNAPSHOT_CMD) \
--config $(TEMPDIR)/goreleaser.yaml \
|| (cat /tmp/quill-*.log && false)"
# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately
.PHONY: compare-mac
compare-mac: $(RESULTSDIR) $(SNAPSHOTDIR) ## Run compare tests on build snapshot binaries and packages (Mac)
$(call title,Running compare test: Run on Mac)
$(COMPARE_DIR)/mac.sh \
$(SNAPSHOTDIR) \
$(COMPARE_DIR) \
$(COMPARE_TEST_IMAGE) \
$(RESULTSDIR)
# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately
.PHONY: compare-linux
compare-linux: compare-test-deb-package-install compare-test-rpm-package-install ## Run compare tests on build snapshot binaries and packages (Linux)
.PHONY: compare-test-deb-package-install
compare-test-deb-package-install: $(RESULTSDIR) $(SNAPSHOTDIR)
$(call title,Running compare test: DEB install)
$(COMPARE_DIR)/deb.sh \
$(SNAPSHOTDIR) \
$(COMPARE_DIR) \
$(COMPARE_TEST_IMAGE) \
$(RESULTSDIR)
.PHONY: compare-test-rpm-package-install
compare-test-rpm-package-install: $(RESULTSDIR) $(SNAPSHOTDIR)
$(call title,Running compare test: RPM install)
$(COMPARE_DIR)/rpm.sh \
$(SNAPSHOTDIR) \
$(COMPARE_DIR) \
$(COMPARE_TEST_IMAGE) \
$(RESULTSDIR)
# note: this is used by CI to determine if the integration test fixture cache (docker image tars) should be busted
cli-fingerprint:
$(call title,CLI test fixture fingerprint)
find test/cli/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/cli/test-fixtures/cache.fingerprint && echo "$(CLI_CACHE_BUSTER)" >> test/cli/test-fixtures/cache.fingerprint
.PHONY: cli
cli: $(SNAPSHOTDIR) ## Run CLI tests
chmod 755 "$(SNAPSHOT_BIN)"
$(SNAPSHOT_BIN) version
SYFT_BINARY_LOCATION='$(SNAPSHOT_BIN)' \
go test -count=1 -timeout=15m -v ./test/cli
.PHONY: changelog
changelog: clean-changelog CHANGELOG.md
@docker run -it --rm \
-v $(shell pwd)/CHANGELOG.md:/CHANGELOG.md \
rawkode/mdv \
-t 748.5989 \
/CHANGELOG.md
CHANGELOG.md:
$(TEMPDIR)/chronicle -vv > CHANGELOG.md
.PHONY: release
release: clean-dist CHANGELOG.md
$(call title,Publishing release artifacts)
# create a config with the dist dir overridden
echo "dist: $(DISTDIR)" > $(TEMPDIR)/goreleaser.yaml
cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml
# note: notarization cannot be done in parallel, thus --parallelism 1
bash -c "\
$(RELEASE_CMD) \
--config $(TEMPDIR)/goreleaser.yaml \
--parallelism 1 \
--release-notes <(cat CHANGELOG.md) \
|| (cat /tmp/quill-*.log && false)"
# TODO: turn this into a post-release hook
# upload the version file that supports the application version update check (excluding pre-releases)
.github/scripts/update-version-file.sh "$(DISTDIR)" "$(VERSION)"
.PHONY: clean
clean: clean-dist clean-snapshot clean-test-image-cache ## Remove previous builds, result reports, and test cache
$(call safe_rm_rf_children,$(RESULTSDIR))
.PHONY: clean-snapshot
clean-snapshot:
$(call safe_rm_rf,$(SNAPSHOTDIR))
rm -f $(TEMPDIR)/goreleaser.yaml
.PHONY: clean-dist
clean-dist: clean-changelog
$(call safe_rm_rf,$(DISTDIR))
rm -f $(TEMPDIR)/goreleaser.yaml
.PHONY: clean-changelog
clean-changelog:
rm -f CHANGELOG.md
clean-test-image-cache: clean-test-image-tar-cache clean-test-image-docker-cache ## Clean test image cache
.PHONY: clear-test-image-tar-cache
clean-test-image-tar-cache:
## Delete all test cache (built docker image tars)
find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" -delete
.PHONY: clear-test-image-docker-cache
clean-test-image-docker-cache:
## Purge all test docker images
docker images --format '{{.ID}} {{.Repository}}' | grep stereoscope-fixture- | awk '{print $$1}' | uniq | xargs -r docker rmi --force
cd syft/pkg/cataloger/binary/test-fixtures && make
.PHONY: show-test-image-cache
show-test-image-cache: ## Show all docker and image tar cache
show-test-image-cache: ## Show all docker and image tar cache
$(call title,Docker daemon cache)
@docker images --format '{{.ID}} {{.Repository}}:{{.Tag}}' | grep stereoscope-fixture- | sort
@@ -399,10 +229,159 @@ show-test-image-cache: ## Show all docker and image tar cache
@find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" | sort
.PHONY: show-test-snapshots
show-test-snapshots: ## Show all test snapshots
show-test-snapshots: ## Show all test snapshots
$(call title,Test snapshots)
@find . -type f -wholename "**/test-fixtures/snapshot/*" | sort
## install.sh testing targets #################################
install-test: $(SNAPSHOT_DIR)
cd test/install && \
make
install-test-cache-save: $(SNAPSHOT_DIR)
cd test/install && \
make save
install-test-cache-load: $(SNAPSHOT_DIR)
cd test/install && \
make load
install-test-ci-mac: $(SNAPSHOT_DIR)
cd test/install && \
make ci-test-mac
.PHONY: generate-compare-file
generate-compare-file:
$(call title,Generating compare test file)
go run ./cmd/syft $(COMPARE_TEST_IMAGE) -o json > $(COMPARE_DIR)/test-fixtures/acceptance-centos-8.2.2004.json
# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately
.PHONY: compare-mac
compare-mac: $(TEMP_DIR) $(SNAPSHOT_DIR) ## Run compare tests on build snapshot binaries and packages (Mac)
$(call title,Running compare test: Run on Mac)
$(COMPARE_DIR)/mac.sh \
$(SNAPSHOT_DIR) \
$(COMPARE_DIR) \
$(COMPARE_TEST_IMAGE) \
$(TEMP_DIR)
# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately
.PHONY: compare-linux
compare-linux: compare-test-deb-package-install compare-test-rpm-package-install ## Run compare tests on build snapshot binaries and packages (Linux)
.PHONY: compare-test-deb-package-install
compare-test-deb-package-install: $(TEMP_DIR) $(SNAPSHOT_DIR)
$(call title,Running compare test: DEB install)
$(COMPARE_DIR)/deb.sh \
$(SNAPSHOT_DIR) \
$(COMPARE_DIR) \
$(COMPARE_TEST_IMAGE) \
$(TEMP_DIR)
.PHONY: compare-test-rpm-package-install
compare-test-rpm-package-install: $(TEMP_DIR) $(SNAPSHOT_DIR)
$(call title,Running compare test: RPM install)
$(COMPARE_DIR)/rpm.sh \
$(SNAPSHOT_DIR) \
$(COMPARE_DIR) \
$(COMPARE_TEST_IMAGE) \
$(TEMP_DIR)
## Code generation targets #################################
.PHONY: generate-json-schema
generate-json-schema: ## Generate a new json schema
cd schema/json && go run generate.go
.PHONY: generate-license-list
generate-license-list: ## Generate an updated spdx license list
go generate ./internal/spdxlicense/...
gofmt -s -w ./internal/spdxlicense
## Build-related targets #################################
.PHONY: build
build: $(SNAPSHOT_DIR) ## Build release snapshot binaries and packages
$(SNAPSHOT_DIR): ## Build snapshot release binaries and packages
$(call title,Building snapshot artifacts)
# create a config with the dist dir overridden
echo "dist: $(SNAPSHOT_DIR)" > $(TEMP_DIR)/goreleaser.yaml
cat .goreleaser.yaml >> $(TEMP_DIR)/goreleaser.yaml
# build release snapshots
$(SNAPSHOT_CMD) --config $(TEMP_DIR)/goreleaser.yaml
.PHONY: changelog
changelog: clean-changelog ## Generate and show the changelog for the current unreleased version
$(CHRONICLE_CMD) -vvv -n --version-file VERSION > $(CHANGELOG)
@$(GLOW_CMD) $(CHANGELOG)
$(CHANGELOG):
$(CHRONICLE_CMD) -vvv > $(CHANGELOG)
.PHONY: release
release:
@.github/scripts/trigger-release.sh
.PHONY: ci-release
ci-release: ci-check clean-dist $(CHANGELOG)
$(call title,Publishing release artifacts)
# create a config with the dist dir overridden
echo "dist: $(DIST_DIR)" > $(TEMP_DIR)/goreleaser.yaml
cat .goreleaser.yaml >> $(TEMP_DIR)/goreleaser.yaml
bash -c "\
$(RELEASE_CMD) \
--config $(TEMP_DIR)/goreleaser.yaml \
--release-notes <(cat $(CHANGELOG)) \
|| (cat /tmp/quill-*.log && false)"
# upload the version file that supports the application version update check (excluding pre-releases)
.github/scripts/update-version-file.sh "$(DIST_DIR)" "$(VERSION)"
.PHONY: ci-check
ci-check:
@.github/scripts/ci-check.sh
## Cleanup targets #################################
.PHONY: clean
clean: clean-dist clean-snapshot clean-test-image-cache ## Remove previous builds, result reports, and test cache
$(call safe_rm_rf_children,$(TEMP_DIR))
.PHONY: clean-snapshot
clean-snapshot:
$(call safe_rm_rf,$(SNAPSHOT_DIR))
rm -f $(TEMP_DIR)/goreleaser.yaml
.PHONY: clean-dist
clean-dist: clean-changelog
$(call safe_rm_rf,$(DIST_DIR))
rm -f $(TEMP_DIR)/goreleaser.yaml
.PHONY: clean-changelog
clean-changelog:
rm -f $(CHANGELOG) VERSION
clean-test-image-cache: clean-test-image-tar-cache clean-test-image-docker-cache ## Clean test image cache
.PHONY: clear-test-image-tar-cache
clean-test-image-tar-cache: ## Delete all test cache (built docker image tars)
find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" -delete
.PHONY: clear-test-image-docker-cache
clean-test-image-docker-cache: ## Purge all test docker images
docker images --format '{{.ID}} {{.Repository}}' | grep stereoscope-fixture- | awk '{print $$1}' | uniq | xargs -r docker rmi --force
## Halp! #################################
.PHONY: help
help: ## Display this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BOLD)$(CYAN)%-25s$(RESET)%s\n", $$1, $$2}'
+37 -21
View File
@@ -38,11 +38,14 @@ For commercial support options with Syft or Grype, please [contact Anchore](http
- Debian (dpkg)
- Dotnet (deps.json)
- Objective-C (cocoapods)
- Elixir (mix)
- Erlang (rebar3)
- Go (go.mod, Go binaries)
- Haskell (cabal, stack)
- Java (jar, ear, war, par, sar)
- Java (jar, ear, war, par, sar, native-image)
- JavaScript (npm, yarn)
- Jenkins Plugins (jpi, hpi)
- Nix (outputs in /nix/store)
- PHP (composer)
- Python (wheel, egg, poetry, requirements.txt)
- Red Hat (rpm)
@@ -75,13 +78,12 @@ choco install syft -y
### Homebrew
```bash
brew tap anchore/syft
brew install syft
```
### Nix
**Note**: Nix packaging of Syft is [community maintained](https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/admin/syft/default.nix). Syft is currently only in the [unstable channel](https://nixos.wiki/wiki/Nix_channels#The_official_channels) awaiting the `22.05` release
**Note**: Nix packaging of Syft is [community maintained](https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/admin/syft/default.nix). Syft is available in the [stable channel](https://nixos.wiki/wiki/Nix_channels#The_official_channels) since NixOS `22.05`.
```bash
nix-env -i syft
@@ -109,9 +111,7 @@ The above output includes only software that is visible in the container (i.e.,
syft <image> --scope all-layers
```
## Supported sources
### Supported sources
Syft can generate a SBOM from a variety of sources:
@@ -140,7 +140,13 @@ 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
If an image source is not provided and cannot be detected from the given reference it is assumed the image should be pulled from the Docker daemon.
If docker is not present, then the Podman daemon is attempted next, followed by reaching out directly to the image registry last.
This default behavior can be overridden with the `default-image-pull-source` configuration option (See [Configuration](https://github.com/anchore/syft#configuration) for more details).
### Default Cataloger Configuration by scan type
##### Image Scanning:
- alpmdb
@@ -178,7 +184,7 @@ registry:yourrepo/yourimage:tag pull image directly from a registry (no
- conan
- hackage
#### Non Default:
##### Non Default:
- cargo-auditable-binary
### Excluding file paths
@@ -212,8 +218,10 @@ Where the `formats` available are:
- `text`: A row-oriented, human-and-machine-friendly output.
- `cyclonedx-xml`: A XML report conforming to the [CycloneDX 1.4 specification](https://cyclonedx.org/specification/overview/).
- `cyclonedx-json`: A JSON report conforming to the [CycloneDX 1.4 specification](https://cyclonedx.org/specification/overview/).
- `spdx-tag-value`: A tag-value formatted report conforming to the [SPDX 2.2 specification](https://spdx.github.io/spdx-spec/).
- `spdx-json`: A JSON report conforming to the [SPDX 2.2 JSON Schema](https://github.com/spdx/spdx-spec/blob/v2.2/schemas/spdx-schema.json).
- `spdx-tag-value`: A tag-value formatted report conforming to the [SPDX 2.3 specification](https://spdx.github.io/spdx-spec/v2.3/).
- `spdx-tag-value@2.2`: A tag-value formatted report conforming to the [SPDX 2.2 specification](https://spdx.github.io/spdx-spec/v2.2.2/).
- `spdx-json`: A JSON report conforming to the [SPDX 2.3 JSON Schema](https://github.com/spdx/spdx-spec/blob/v2.3/schemas/spdx-schema.json).
- `spdx-json@2.2`: A JSON report conforming to the [SPDX 2.2 JSON Schema](https://github.com/spdx/spdx-spec/blob/v2.2/schemas/spdx-schema.json).
- `github`: A JSON report conforming to GitHub's dependency snapshot format.
- `table`: A columnar summary (default).
- `template`: Lets the user specify the output format. See ["Using templates"](#using-templates) below.
@@ -366,6 +374,8 @@ syft convert sbom.syft.json -o cyclonedx-json=sbom.cdx.json # convert it to Cyc
### Keyless support
Syft supports generating attestations using cosign's [keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) signatures.
Note: users need to have >= v1.12.0 of cosign installed for this command to function
To use this feature with a format like CycloneDX json simply run:
```
syft attest --output cyclonedx-json <IMAGE WITH OCI WRITE ACCESS>
@@ -388,7 +398,7 @@ Certificate subject: test.email@testdomain.com
Certificate issuer URL: https://accounts.google.com
```
#### Local private key support
### Local private key support
To generate an SBOM attestation for a container image using a local private key:
```
@@ -431,6 +441,10 @@ file: ""
# same as SYFT_CHECK_FOR_APP_UPDATE env var
check-for-app-update: true
# allows users to specify which image source should be used to generate the sbom
# valid values are: registry, docker, podman
default-image-pull-source: ""
# a list of globs to exclude from scanning. same as --exclude ; for example:
# exclude:
# - "/etc/**"
@@ -489,16 +503,15 @@ package:
# same as -s ; SYFT_PACKAGE_CATALOGER_SCOPE env var
scope: "squashed"
# cataloging file classifications is exposed through the power-user subcommand
file-classification:
cataloger:
# enable/disable cataloging of file classifications
# SYFT_FILE_CLASSIFICATION_CATALOGER_ENABLED env var
enabled: true
# the search space to look for file classifications (options: all-layers, squashed)
# SYFT_FILE_CLASSIFICATION_CATALOGER_SCOPE env var
scope: "squashed"
golang:
# search for go package licences in the GOPATH of the system running Syft, note that this is outside the
# container filesystem and potentially outside the root of a local directory scan
# SYFT_GOLANG_SEARCH_LOCAL_MOD_CACHE_LICENSES env var
search-local-mod-cache-licenses: false
# specify an explicit go mod cache directory, if unset this defaults to $GOPATH/pkg/mod or $HOME/go/pkg/mod
# SYFT_GOLANG_LOCAL_MOD_CACHE_DIR env var
local-mod-cache-dir: ""
# cataloging file contents is exposed through the power-user subcommand
file-contents:
@@ -534,6 +547,9 @@ file-metadata:
# SYFT_FILE_METADATA_DIGESTS env var
digests: ["sha256"]
# maximum number of workers used to process the list of package catalogers in parallel
parallelism: 1
# cataloging secrets is exposed through the power-user subcommand
secrets:
cataloger:
+51 -43
View File
@@ -1,14 +1,49 @@
# Release Process
# Release
## Creating a release
This release process itself should be as automated as possible, and has only a few steps:
1. **Trigger a new release with `make release`**. At this point you'll see a preview
changelog in the terminal. If you're happy with the changelog, press `y` to continue, otherwise
you can abort and adjust the labels on the PRs and issues to be included in the release and
re-run the release trigger command.
1. A release admin must approve the release on the GitHub Actions release pipeline run page.
Once approved, the release pipeline will generate all assets and publish a GitHub Release.
1. If there is a release Milestone, close it.
Ideally releasing should be done often with small increments when possible. Unless a
breaking change is blocking the release, or no fixes/features have been merged, a good
target release cadence is between every 1 or 2 weeks.
## Retracting a release
If a release is found to be problematic, it can be retracted with the following steps:
- Deleting the GitHub Release
- Untag the docker images in the `ghcr.io` and `docker.io` registries
- Revert the brew formula in [`anchore/homebrew-syft`](https://github.com/anchore/homebrew-syft) to point to the previous release
- Add a new `retract` entry in the go.mod for the versioned release
**Note**: do not delete release tags from the git repository since there may already be references to the release
in the go proxy, which will cause confusion when trying to reuse the tag later (the H1 hash will not match and there
will be a warning when users try to pull the new release).
## Background
A good release process has the following qualities:
1. There is a way to plan what should be in a release
1. There is a way to see what is actually in a release
1. Allow for different kinds of releases (major breaking vs backwards compatible
enhancements vs patch updates)
1. Allow for different kinds of releases (major breaking vs backwards compatible enhancements vs patch updates)
1. Specify a repeatable way to build and publish software artifacts
## Planning a release
### Planning a release
To indicate a set of features to be released together add each issue to an in-repository
Milestone named with major-minor version to be released (e.g. `v0.1`). It is OK for other
@@ -21,15 +56,13 @@ completed, would allow the release to be considered complete. A Milestone is onl
Not all releases need to be planned. For instance, patch releases for fixes should be
released when they are ready and when releasing would not interfere with another current
release (where some partial or breaking features have already been merged). Beta releases
and release candidates should not be independently planned from the non-beta release. That
is, the features for a `v0.1-beta.1` release should be planned under the `v0.1` Milestone,
not under a separate `v0.1-beta.1` Milestone.
release (where some partial or breaking features have already been merged).
Unless necessary, feature releases should be small and frequent, which may obviate the
need for regular release planning under a Milestone.
## What is in a release
### What is in a release
Milestones are specifically for planning a release, not necessarily tracking all changes
that a release may bring (and more importantly, not all releases are necessarily planned
@@ -42,9 +75,9 @@ Changelog line. Furthermore, there should be a place to see all released version
release date for each release, the semantic version of the release, and the set of changes
for each release.
This project auto-generates the Changelog contents for each current release and posts the
generated contents to the GitHub Release page. Leveraging the GitHub Releases feature
allows GitHub to manage the Changelog on each release outside of the git repository while
**This project auto-generates the Changelog contents for each current release and posts the
generated contents to the GitHub Release page**. Leveraging the GitHub Releases feature
allows GitHub to manage the Changelog on each release outside of the git source tree while
still being hosted with the released assets.
The Changelog is generated from the metadata from in-repository issues and PRs, using
@@ -60,45 +93,20 @@ The above suggestions imply that we should:
- The appropriate label is applied to PRs and/or issues to drive specific change type
sections (deprecated, breaking, security, bug, etc)
With this approach as we cultivate good organization of PRs and issues we automatically
get an equally good Changelog.
**With this approach as we cultivate good organization of PRs and issues we automatically
get an equally good Changelog.**
## Major, minor, and patch releases
### Major, minor, and patch releases
The latest version of the tool is the only supported version, which implies that multiple
parallel release branches will not be a regular process (if ever). Multiple releases can
be planned in parallel, however, only one can be actively developed at a time. That is, if
PRs attached to a release Milestone have been merged into the main branch, that release is
now the "next" release. This implies that the source of truth for release lies with the
git log and Changelog, not with the release Milestones (which are purely for planning and
now the "next" release. **This implies that the source of truth for release lies with the
git log and Changelog, not with the release Milestones** (which are purely for planning and
tracking).
Semantic versioning should be used to indicate breaking changes, new features, and fixes.
The exception to this is `< 1.0`, where the major version is not bumped for breaking changes,
instead the minor version indicates both new features and breaking changes.
## Cutting a release
Ideally releasing should be done often with small increments when possible. Unless a
breaking change is blocking the release, or no fixes/features have been merged, a good
target release cadence is between every 2 or 4 weeks.
This release process itself should be as automated as possible, and have only a few steps:
1. Tag the main branch with a full semantic-version, prefixed with a `v`. If there is a
milestone with a partial version, the full version should be used for the git tag (e.g.
with a Milestone of `v0.1` the tag should be `v0.1.0`). You can determine the changes going
into a release by running `make changelog-unreleased`. Use this change list to determine the
release increment. After determining the release increment (major, minor, patch), create the tag.
Given the above example the command to create the tag would be `git tag v0.1.0`.
1. Push the tag. Given the above example the command to push the tag would be `git push origin v0.1.0`.
1. A release admin must approve the release on the GitHub Actions release pipeline run page.
Once approved, the release pipeline will generate all assets and draft a GitHub Release.
1. Navigate to the GitHub Release draft page to review the final changelog and publish the
release. Once published, a release-follow-up pipeline will publish derivative artifacts
(docker image to DockerHub, brew formula to the external homebrew git repo, etc).
1. If there is a release Milestone, close it.
+1 -1
View File
@@ -1,5 +1,5 @@
# See documentation here: https://github.com/artifacthub/hub/blob/v1.6.0/docs/metadata/artifacthub-repo.yml
repositoryID: eced152f-b15d-4879-8b3b-1175397192ba
owners:
- name: wagoodman
email: wagoodman@gmail.com
+17 -32
View File
@@ -4,7 +4,6 @@ import (
"fmt"
"log"
sigopts "github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -15,33 +14,26 @@ import (
)
const (
attestExample = ` {{.appName}} {{.command}} --output [FORMAT] --key [KEY] alpine:latest
Supports the following image sources:
{{.appName}} {{.command}} --key [KEY] yourrepo/yourimage:tag defaults to using images from a Docker daemon. If Docker is not present, the image is pulled directly from the registry.
{{.appName}} {{.command}} --key [KEY] path/to/a/file/or/dir only for OCI tar or OCI directory
attestExample = ` {{.appName}} {{.command}} --output [FORMAT] alpine:latest defaults to using images from a Docker daemon. If Docker is not present, the image is pulled directly from the registry
`
attestSchemeHelp = "\n" + indent + schemeHelpHeader + "\n" + imageSchemeHelp
attestHelp = attestExample + attestSchemeHelp
attestHelp = attestExample + attestSchemeHelp
)
func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions) *cobra.Command {
ao := options.AttestOptions{}
func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions, po *options.PackagesOptions, ao *options.AttestOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "attest --output [FORMAT] --key [KEY] [SOURCE]",
Short: "Generate a package SBOM as an attestation for the given [SOURCE] container image",
Long: "Generate a packaged-based Software Bill Of Materials (SBOM) from a container image as the predicate of an in-toto attestation",
Use: "attest --output [FORMAT] <IMAGE>",
Short: "Generate an SBOM as an attestation for the given [SOURCE] container image",
Long: "Generate a packaged-based Software Bill Of Materials (SBOM) from a container image as the predicate of an in-toto attestation that will be uploaded to the image registry",
Example: internal.Tprintf(attestHelp, map[string]interface{}{
"appName": internal.ApplicationName,
"command": "attest",
}),
Args: func(cmd *cobra.Command, args []string) error {
// run to unmarshal viper object onto app config
// the viper object correctly
if err := app.LoadAllValues(v, ro.Config); err != nil {
return fmt.Errorf("invalid application config: %v", err)
return fmt.Errorf("unable to load configuration: %w", err)
}
// configure logging for command
newLogWrapper(app)
logApplicationConfig(app)
return validateArgs(cmd, args)
@@ -49,29 +41,22 @@ func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions) *c
SilenceUsage: true,
SilenceErrors: true,
RunE: func(cmd *cobra.Command, args []string) error {
// this MUST be called first to make sure app config decodes
// the viper object correctly
if app.CheckForAppUpdate {
checkForApplicationUpdate()
}
// build cosign key options for attestation
ko := sigopts.KeyOpts{
KeyRef: app.Attest.KeyRef,
FulcioURL: app.Attest.FulcioURL,
IDToken: app.Attest.FulcioIdentityToken,
InsecureSkipFulcioVerify: app.Attest.InsecureSkipFulcioVerify,
RekorURL: app.Attest.RekorURL,
OIDCIssuer: app.Attest.OIDCIssuer,
OIDCClientID: app.Attest.OIDCClientID,
OIDCRedirectURL: app.Attest.OIDCRedirectURL,
}
return attest.Run(cmd.Context(), app, ko, args)
return attest.Run(cmd.Context(), app, args)
},
}
err := ao.AddFlags(cmd, v)
// syft attest is an enhancement of the packages command, so it should have the same flags
err := po.AddFlags(cmd, v)
if err != nil {
log.Fatal(err)
}
// syft attest has its own options not included as part of the packages command
err = ao.AddFlags(cmd, v)
if err != nil {
log.Fatal(err)
}
+152 -306
View File
@@ -1,105 +1,60 @@
package attest
import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/in-toto/in-toto-golang/in_toto"
sigopts "github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/sigstore/cosign/cmd/cosign/cli/rekor"
"github.com/sigstore/cosign/cmd/cosign/cli/sign"
"github.com/sigstore/cosign/pkg/cosign"
"github.com/sigstore/cosign/pkg/cosign/attestation"
cbundle "github.com/sigstore/cosign/pkg/cosign/bundle"
"github.com/sigstore/cosign/pkg/oci/mutate"
ociremote "github.com/sigstore/cosign/pkg/oci/remote"
"github.com/sigstore/cosign/pkg/oci/static"
sigs "github.com/sigstore/cosign/pkg/signature"
"github.com/sigstore/cosign/pkg/types"
"github.com/sigstore/rekor/pkg/generated/client"
"github.com/sigstore/rekor/pkg/generated/models"
"github.com/sigstore/sigstore/pkg/signature/dsse"
signatureoptions "github.com/sigstore/sigstore/pkg/signature/options"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"golang.org/x/exp/slices"
"github.com/anchore/stereoscope"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/cmd/syft/cli/eventloop"
"github.com/anchore/syft/cmd/syft/cli/options"
"github.com/anchore/syft/cmd/syft/cli/packages"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/config"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/ui"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/formats/cyclonedxjson"
"github.com/anchore/syft/syft/formats/spdx22json"
"github.com/anchore/syft/syft/event/monitor"
"github.com/anchore/syft/syft/formats/syftjson"
"github.com/anchore/syft/syft/formats/table"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
)
var (
allowedAttestFormats = []sbom.FormatID{
syftjson.ID,
spdx22json.ID,
cyclonedxjson.ID,
}
intotoJSONDsseType = `application/vnd.in-toto+json`
)
func Run(ctx context.Context, app *config.Application, ko sigopts.KeyOpts, args []string) error {
// We cannot generate an attestation for more than one output
if len(app.Outputs) > 1 {
return fmt.Errorf("unable to generate attestation for more than one output")
}
// can only be an image for attestation or OCI DIR
userInput := args[0]
si, err := parseImageSource(userInput, app)
func Run(_ context.Context, app *config.Application, args []string) error {
err := ValidateOutputOptions(app)
if err != nil {
return err
}
output := parseAttestationOutput(app.Outputs)
format := syft.FormatByName(output)
// user typo or unknown outputs provided
if format == nil {
format = syft.FormatByID(syftjson.ID) // default attestation format
}
predicateType := formatPredicateType(format)
if predicateType == "" {
return fmt.Errorf(
"could not produce attestation predicate for given format: %q. Available formats: %+v",
options.FormatAliases(format.ID()),
options.FormatAliases(allowedAttestFormats...),
)
writer, err := options.MakeWriter(app.Outputs, app.File, app.OutputTemplatePath)
if err != nil {
return fmt.Errorf("unable to write to report destination: %w", err)
}
if app.Attest.KeyRef != "" {
passFunc, err := selectPassFunc(app.Attest.KeyRef, app.Attest.Password)
if err != nil {
return err
defer func() {
if err := writer.Close(); err != nil {
fmt.Printf("unable to close report destination: %+v", err)
}
}()
ko.PassFunc = passFunc
}
sv, err := sign.SignerFromKeyOpts(ctx, "", "", ko)
// could be an image or a directory, with or without a scheme
// TODO: validate that source is image
userInput := args[0]
si, err := source.ParseInputWithName(userInput, app.Platform, app.Name, app.DefaultImagePullSource)
if err != nil {
return err
return fmt.Errorf("could not generate source input for packages command: %w", err)
}
if si.Scheme != source.ImageScheme {
return fmt.Errorf("attestations are only supported for oci images at this time")
}
defer sv.Close()
eventBus := partybus.NewBus()
stereoscope.SetBus(eventBus)
@@ -107,7 +62,7 @@ func Run(ctx context.Context, app *config.Application, ko sigopts.KeyOpts, args
subscription := eventBus.Subscribe()
return eventloop.EventLoop(
execWorker(app, *si, format, predicateType, sv),
execWorker(app, *si, writer),
eventloop.SetupSignals(),
subscription,
stereoscope.Cleanup,
@@ -115,284 +70,175 @@ func Run(ctx context.Context, app *config.Application, ko sigopts.KeyOpts, args
)
}
func parseAttestationOutput(outputs []string) (format string) {
if len(outputs) == 0 {
outputs = append(outputs, string(syftjson.ID))
func buildSBOM(app *config.Application, si source.Input, writer sbom.Writer, errs chan error) ([]byte, error) {
src, cleanup, err := source.New(si, app.Registry.ToOptions(), app.Exclusions)
if cleanup != nil {
defer cleanup()
}
return outputs[0]
}
func parseImageSource(userInput string, app *config.Application) (s *source.Input, err error) {
si, err := source.ParseInput(userInput, app.Platform, false)
if err != nil {
return nil, fmt.Errorf("could not generate source input for attest command: %w", err)
return nil, fmt.Errorf("failed to construct source from user input %q: %w", si.UserInput, err)
}
switch si.Scheme {
case source.ImageScheme, source.UnknownScheme:
// at this point we know that it cannot be dir: or file: schemes;
// we will assume that the unknown scheme could represent an image;
si.Scheme = source.ImageScheme
default:
return nil, fmt.Errorf("attest command can only be used with image sources but discovered %q when given %q", si.Scheme, userInput)
s, err := packages.GenerateSBOM(src, errs, app)
if err != nil {
return nil, err
}
// if the original detection was from the local daemon we want to short circuit
// that and attempt to generate the image source from its current registry source instead
switch si.ImageSource {
case image.UnknownSource, image.OciRegistrySource:
si.ImageSource = image.OciRegistrySource
case image.SingularitySource:
default:
return nil, fmt.Errorf("attest command can only be used with image sources fetch directly from the registry, but discovered an image source of %q when given %q", si.ImageSource, userInput)
if s == nil {
return nil, fmt.Errorf("no SBOM produced for %q", si.UserInput)
}
return si, nil
// note: only works for single format no multi writer support
sBytes, err := writer.Bytes(*s)
if err != nil {
return nil, fmt.Errorf("unable to build SBOM bytes: %w", err)
}
return sBytes, nil
}
func execWorker(app *config.Application, sourceInput source.Input, format sbom.Format, predicateType string, sv *sign.SignerVerifier) <-chan error {
//nolint:funlen
func execWorker(app *config.Application, si source.Input, writer sbom.Writer) <-chan error {
errs := make(chan error)
go func() {
defer close(errs)
src, cleanup, err := source.NewFromRegistry(sourceInput, app.Registry.ToOptions(), app.Exclusions)
if cleanup != nil {
defer cleanup()
}
sBytes, err := buildSBOM(app, si, writer, errs)
if err != nil {
errs <- fmt.Errorf("failed to construct source from user input %q: %w", sourceInput.UserInput, err)
errs <- fmt.Errorf("unable to build SBOM: %w", err)
return
}
s, err := packages.GenerateSBOM(src, errs, app)
if err != nil {
errs <- err
return
}
// TODO: add multi writer support
for _, o := range app.Outputs {
f, err := os.CreateTemp("", o)
if err != nil {
errs <- fmt.Errorf("unable to create temp file: %w", err)
return
}
sbomBytes, err := syft.Encode(*s, format)
if err != nil {
errs <- err
return
}
defer f.Close()
defer os.Remove(f.Name())
signedPayload, err := generateAttestation(sourceInput, sbomBytes, src, sv, predicateType)
if err != nil {
errs <- err
return
}
if _, err := f.Write(sBytes); err != nil {
errs <- fmt.Errorf("unable to write SBOM to temp file: %w", err)
return
}
err = publishAttestation(app, signedPayload, src, sv)
if err != nil {
errs <- err
return
// TODO: what other validation here besides binary name?
cmd := "cosign"
if !commandExists(cmd) {
errs <- fmt.Errorf("unable to find cosign in PATH; make sure you have it installed")
return
}
// Select Cosign predicate type based on defined output type
// As orientation, check: https://github.com/sigstore/cosign/blob/main/pkg/cosign/attestation/attestation.go
var predicateType string
switch strings.ToLower(o) {
case "cyclonedx-json":
predicateType = "cyclonedx"
case "spdx-tag-value":
predicateType = "spdx"
case "spdx-json":
predicateType = "spdxjson"
default:
predicateType = "custom"
}
args := []string{"attest", si.UserInput, "--predicate", f.Name(), "--type", predicateType}
if app.Attest.Key != "" {
args = append(args, "--key", app.Attest.Key)
}
execCmd := exec.Command(cmd, args...)
execCmd.Env = os.Environ()
if app.Attest.Key != "" {
execCmd.Env = append(execCmd.Env, fmt.Sprintf("COSIGN_PASSWORD=%s", app.Attest.Password))
} else {
// no key provided, use cosign's keyless mode
execCmd.Env = append(execCmd.Env, "COSIGN_EXPERIMENTAL=1")
}
// bus adapter for ui to hook into stdout via an os pipe
r, w, err := os.Pipe()
if err != nil {
errs <- fmt.Errorf("unable to create os pipe: %w", err)
return
}
defer w.Close()
b := &busWriter{r: r, w: w, mon: progress.NewManual(-1)}
execCmd.Stdout = b
execCmd.Stderr = b
defer b.mon.SetCompleted()
// attest the SBOM
err = execCmd.Run()
if err != nil {
b.mon.SetError(err)
errs <- fmt.Errorf("unable to attest SBOM: %w", err)
return
}
}
bus.Publish(partybus.Event{
Type: event.Exit,
Value: func() error {
return nil
},
Type: event.Exit,
Value: func() error { return nil },
})
}()
return errs
}
func generateAttestation(si source.Input, predicate []byte, src *source.Source, sv *sign.SignerVerifier, predicateType string) ([]byte, error) {
var h v1.Hash
switch si.ImageSource {
case image.OciRegistrySource:
switch len(src.Image.Metadata.RepoDigests) {
case 0:
return nil, fmt.Errorf("cannot generate attestation since no repo digests were found; make sure you're passing an OCI registry source for the attest command")
case 1:
d, err := name.NewDigest(src.Image.Metadata.RepoDigests[0])
if err != nil {
return nil, err
}
h, err = v1.NewHash(d.Identifier())
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("cannot generate attestation since multiple repo digests were found for the image: %+v", src.Image.Metadata.RepoDigests)
}
case image.SingularitySource:
var err error
h, err = v1.NewHash(src.Image.Metadata.ID)
if err != nil {
return nil, err
}
}
sh, err := attestation.GenerateStatement(attestation.GenerateOpts{
Predicate: bytes.NewBuffer(predicate),
Type: predicateType,
Digest: h.Hex,
})
if err != nil {
return nil, err
}
payload, err := json.Marshal(sh)
if err != nil {
return nil, err
}
wrapped := dsse.WrapSigner(sv, intotoJSONDsseType)
return wrapped.SignMessage(bytes.NewReader(payload), signatureoptions.WithContext(context.Background()))
}
// publishAttestation publishes signedPayload to the location specified by the user.
func publishAttestation(app *config.Application, signedPayload []byte, src *source.Source, sv *sign.SignerVerifier) error {
switch {
// We want to give the option to not upload the generated attestation
// if passed or if the user is using local PKI
case app.Attest.NoUpload || app.Attest.KeyRef != "":
if app.File != "" {
return os.WriteFile(app.File, signedPayload, 0600)
}
_, err := os.Stdout.Write(signedPayload)
return err
default:
ref, err := name.ParseReference(src.Metadata.ImageMetadata.UserInput)
if err != nil {
return err
}
digest, err := ociremote.ResolveDigest(ref)
if err != nil {
return err
}
return uploadAttestation(app, signedPayload, digest, sv)
}
}
func trackUploadAttestation() (*progress.Stage, *progress.Manual) {
stage := &progress.Stage{}
prog := &progress.Manual{}
bus.Publish(partybus.Event{
Type: event.UploadAttestation,
Value: progress.StagedProgressable(&struct {
progress.Stager
progress.Progressable
}{
Stager: stage,
Progressable: prog,
}),
})
return stage, prog
}
// uploads signed SBOM payload to Rekor transparency log along with key information;
// returns a bundle for attestation annotations
// rekor bundle includes a signed payload and rekor timestamp;
// the bundle is then wrapped onto an OCI signed entity and uploaded to
// the user's image's OCI registry repository as *.att
func uploadAttestation(app *config.Application, signedPayload []byte, digest name.Digest, sv *sign.SignerVerifier) error {
// add application/vnd.dsse.envelope.v1+json as media type for other applications to decode attestation
opts := []static.Option{static.WithLayerMediaType(types.DssePayloadType)}
if sv.Cert != nil {
opts = append(opts, static.WithCertChain(sv.Cert, sv.Chain))
}
stage, prog := trackUploadAttestation()
defer prog.SetCompleted() // just in case we return early
prog.Total = 2
stage.Current = "uploading signing information to transparency log"
// uploads payload to Rekor transparency log along with key information;
// returns bundle for attesation annotations
// rekor bundle includes a signed payload and rekor timestamp;
// the bundle is then wrapped onto an OCI signed entity and uploaded to
// the user's image's OCI registry repository as *.att
bundle, err := uploadToTlog(context.TODO(), sv, app.Attest.RekorURL, func(r *client.Rekor, b []byte) (*models.LogEntryAnon, error) {
return cosign.TLogUploadInTotoAttestation(context.TODO(), r, signedPayload, b)
})
func ValidateOutputOptions(app *config.Application) error {
err := packages.ValidateOutputOptions(app)
if err != nil {
return err
}
prog.N = 1
stage.Current = "uploading attestation to OCI registry"
// add bundle OCI attestation that is uploaded to
opts = append(opts, static.WithBundle(bundle))
sig, err := static.NewAttestation(signedPayload, opts...)
if err != nil {
return err
if len(app.Outputs) > 1 {
return fmt.Errorf("multiple SBOM format is not supported for attest at this time")
}
se, err := ociremote.SignedEntity(digest)
if err != nil {
return err
// cannot use table as default output format when using template output
if slices.Contains(app.Outputs, table.ID.String()) {
app.Outputs = []string{syftjson.ID.String()}
}
newSE, err := mutate.AttachAttestationToEntity(se, sig)
if err != nil {
return err
}
// Publish the attestations associated with this entity
err = ociremote.WriteAttestations(digest.Repository, newSE)
if err != nil {
return err
}
prog.SetCompleted()
return nil
}
func formatPredicateType(format sbom.Format) string {
switch format.ID() {
case spdx22json.ID:
return in_toto.PredicateSPDX
case cyclonedxjson.ID:
return in_toto.PredicateCycloneDX
case syftjson.ID:
return "https://syft.dev/bom"
default:
return ""
}
type busWriter struct {
w *os.File
r *os.File
hasWritten bool
mon *progress.Manual
}
type tlogUploadFn func(*client.Rekor, []byte) (*models.LogEntryAnon, error)
func uploadToTlog(ctx context.Context, sv *sign.SignerVerifier, rekorURL string, upload tlogUploadFn) (*cbundle.RekorBundle, error) {
var rekorBytes []byte
// Upload the cert or the public key, depending on what we have
if sv.Cert != nil {
rekorBytes = sv.Cert
} else {
pemBytes, err := sigs.PublicKeyPem(sv, signatureoptions.WithContext(ctx))
if err != nil {
return nil, err
}
rekorBytes = pemBytes
func (b *busWriter) Write(p []byte) (n int, err error) {
if !b.hasWritten {
b.hasWritten = true
bus.Publish(
partybus.Event{
Type: event.AttestationStarted,
Source: monitor.GenericTask{
Title: monitor.Title{
Default: "Create attestation",
WhileRunning: "Creating attestation",
OnSuccess: "Created attestation",
},
Context: "cosign",
},
Value: &monitor.ShellProgress{
Reader: b.r,
Manual: b.mon,
},
},
)
}
return b.w.Write(p)
}
rekorClient, err := rekor.NewClient(rekorURL)
if err != nil {
return nil, err
}
entry, err := upload(rekorClient, rekorBytes)
if err != nil {
return nil, err
}
if entry.LogIndex != nil {
log.Debugf("transparency log entry created with index: %v", *entry.LogIndex)
}
return cbundle.EntryToBundle(entry), nil
func commandExists(cmd string) bool {
_, err := exec.LookPath(cmd)
return err == nil
}
-57
View File
@@ -1,57 +0,0 @@
package attest
import (
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/sigstore/cosign/pkg/cosign"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
)
func selectPassFunc(keypath, password string) (cosign.PassFunc, error) {
keyContents, err := os.ReadFile(keypath)
if err != nil {
return nil, err
}
var fn cosign.PassFunc = func(bool) (b []byte, err error) { return nil, nil }
_, err = cosign.LoadPrivateKey(keyContents, nil)
if err != nil {
fn = func(bool) (b []byte, err error) {
return fetchPassword(password)
}
}
return fn, nil
}
func fetchPassword(password string) (b []byte, err error) {
potentiallyPipedInput, err := internal.IsPipedInput()
if err != nil {
log.Warnf("unable to determine if there is piped input: %+v", err)
}
switch {
case password != "":
return []byte(password), nil
case potentiallyPipedInput:
// handle piped in passwords
pwBytes, err := io.ReadAll(os.Stdin)
if err != nil {
return nil, fmt.Errorf("unable to get password from stdin: %w", err)
}
// be resilient to input that may have newline characters (in case someone is using echo without -n)
cleanPw := strings.TrimRight(string(pwBytes), "\n")
return []byte(cleanPw), nil
case internal.IsTerminal():
return cosign.GetPassFromTerm(false)
}
return nil, errors.New("no method available to fetch password")
}
+10 -14
View File
@@ -26,14 +26,14 @@ import (
const indent = " "
// New constructs the `syft packages` command, aliases the root command to `syft packages`,
// and constructs the `syft power-user` and `syft attest` commands. It is also responsible for
// and constructs the `syft power-user` command. It is also responsible for
// organizing flag usage and injecting the application config for each command.
// It also constructs the syft attest command and the syft version command.
// Because of how the `cobra` library behaves, the application's configuration is initialized
// 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
func New() (*cobra.Command, error) {
app := &config.Application{}
@@ -45,15 +45,17 @@ func New() (*cobra.Command, error) {
// we also need the command to have information about the `root` options because of this alias
ro := &options.RootOptions{}
po := &options.PackagesOptions{}
ao := &options.AttestOptions{}
packagesCmd := Packages(v, app, ro, po)
// 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, po)
attestCmd := Attest(v, app, ro, po, ao)
// rootCmd is currently an alias for the packages command
rootCmd := &cobra.Command{
Use: fmt.Sprintf("%s [SOURCE]", internal.ApplicationName),
Short: packagesCmd.Short,
Long: packagesCmd.Long,
Args: packagesCmd.Args,
@@ -75,11 +77,7 @@ func New() (*cobra.Command, error) {
if err != nil {
return nil, err
}
// attest also uses flags from the packagesCmd since it generates an sbom
err = po.AddFlags(attestCmd, v)
if err != nil {
return nil, err
}
// poweruser also uses the packagesCmd flags since it is a specialized version of the command
err = po.AddFlags(poweruserCmd, v)
if err != nil {
@@ -89,13 +87,11 @@ func New() (*cobra.Command, error) {
// commands to add to root
cmds := []*cobra.Command{
packagesCmd,
attestCmd,
poweruserCmd,
convertCmd,
poweruserCmd,
poweruserCmd,
Completion(),
attestCmd,
Version(v, app),
cranecmd.NewCmdAuthLogin("syft"),
cranecmd.NewCmdAuthLogin("syft"), // syft login uses the same command as crane
}
// Add sub-commands.
-54
View File
@@ -1,54 +0,0 @@
package cli
import (
"os"
"github.com/spf13/cobra"
)
func Completion() *cobra.Command {
cmd := &cobra.Command{
Use: "completion [bash|zsh|fish]",
Short: "Generate a shell completion for Syft (listing local docker images)",
Long: `To load completions (docker image list):
Bash:
$ source <(syft completion bash)
# To load completions for each session, execute once:
Linux:
$ syft completion bash > /etc/bash_completion.d/syft
MacOS:
$ syft completion bash > /usr/local/etc/bash_completion.d/syft
Zsh:
# If shell completion is not already enabled in your environment you will need
# to enable it. You can execute the following once:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
# To load completions for each session, execute once:
$ syft completion zsh > "${fpath[1]}/_syft"
# You will need to start a new shell for this setup to take effect.
Fish:
$ syft completion fish | source
# To load completions for each session, execute once:
$ syft completion fish > ~/.config/fish/completions/syft.fish
`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish"},
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
RunE: func(cmd *cobra.Command, args []string) error {
var err error
switch args[0] {
case "bash":
err = cmd.Root().GenBashCompletion(os.Stdout)
case "zsh":
err = cmd.Root().GenZshCompletion(os.Stdout)
case "fish":
err = cmd.Root().GenFishCompletion(os.Stdout, true)
}
if err != nil {
return err
}
return nil
},
}
return cmd
}
+3 -2
View File
@@ -14,8 +14,9 @@ import (
)
const (
convertExample = ` {{.appName}} {{.command}} img.syft.json -o spdx-json convert a syft SBOM to spdx-json, output goes to stdout in table format, by default
{{.appName}} {{.command}} img.syft.json -o cyclonedx-json=img.cdx.json convert a syft SBOM to CycloneDX, output goes to a file named img.cdx.json
convertExample = ` {{.appName}} {{.command}} img.syft.json -o spdx-json convert a syft SBOM to spdx-json, output goes to stdout
{{.appName}} {{.command}} img.syft.json -o cyclonedx-json=img.cdx.json convert a syft SBOM to CycloneDX, output is written to the file "img.cdx.json""
{{.appName}} {{.command}} - -o spdx-json convert an SBOM from STDIN to spdx-json
`
)
+20 -9
View File
@@ -3,17 +3,18 @@ package convert
import (
"context"
"fmt"
"io"
"os"
"github.com/anchore/syft/cmd/syft/cli/options"
"github.com/anchore/syft/internal/config"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/formats"
)
func Run(ctx context.Context, app *config.Application, args []string) error {
func Run(_ context.Context, app *config.Application, args []string) error {
log.Warn("convert is an experimental feature, run `syft convert -h` for help")
writer, err := options.MakeWriter(app.Outputs, app.File, "")
writer, err := options.MakeWriter(app.Outputs, app.File, app.OutputTemplatePath)
if err != nil {
return err
}
@@ -26,13 +27,23 @@ func Run(ctx context.Context, app *config.Application, args []string) error {
// this can only be a SBOM file
userInput := args[0]
f, err := os.Open(userInput)
if err != nil {
return fmt.Errorf("failed to open SBOM file: %w", err)
}
defer f.Close()
sbom, _, err := syft.Decode(f)
var reader io.ReadCloser
if userInput == "-" {
reader = os.Stdin
} else {
f, err := os.Open(userInput)
if err != nil {
return fmt.Errorf("failed to open SBOM file: %w", err)
}
defer func() {
_ = f.Close()
}()
reader = f
}
sbom, _, err := formats.Decode(reader)
if err != nil {
return fmt.Errorf("failed to decode SBOM: %w", err)
}
-2
View File
@@ -15,8 +15,6 @@ 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
func EventLoop(workerErrs <-chan error, signals <-chan os.Signal, subscription *partybus.Subscription, cleanupFn func(), uxs ...ui.UI) error {
defer cleanupFn()
events := subscription.Events()
+1 -33
View File
@@ -22,7 +22,6 @@ func Tasks(app *config.Application) ([]Task, error) {
generateCatalogFileMetadataTask,
generateCatalogFileDigestsTask,
generateCatalogSecretsTask,
generateCatalogFileClassificationsTask,
generateCatalogContentsTask,
}
@@ -47,14 +46,11 @@ func generateCatalogPackagesTask(app *config.Application) (Task, error) {
task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
packageCatalog, relationships, theDistro, err := syft.CatalogPackages(src, app.ToCatalogerConfig())
if err != nil {
return nil, err
}
results.PackageCatalog = packageCatalog
results.LinuxDistribution = theDistro
return relationships, nil
return relationships, err
}
return task, nil
@@ -162,34 +158,6 @@ func generateCatalogSecretsTask(app *config.Application) (Task, error) {
return task, nil
}
func generateCatalogFileClassificationsTask(app *config.Application) (Task, error) {
if !app.FileClassification.Cataloger.Enabled {
return nil, nil
}
// TODO: in the future we could expose out the classifiers via configuration
classifierCataloger, err := file.NewClassificationCataloger(file.DefaultClassifiers)
if err != nil {
return nil, err
}
task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(app.FileClassification.Cataloger.ScopeOpt)
if err != nil {
return nil, err
}
result, err := classifierCataloger.Catalog(resolver)
if err != nil {
return nil, err
}
results.FileClassifications = result
return nil, nil
}
return task, nil
}
func generateCatalogContentsTask(app *config.Application) (Task, error) {
if !app.FileContents.Cataloger.Enabled {
return nil, nil
+6 -57
View File
@@ -6,72 +6,21 @@ import (
"github.com/spf13/viper"
)
const defaultKeyFileName = "cosign.key"
type AttestOptions struct {
Key string
Cert string
CertChain string
NoUpload bool
Force bool
Recursive bool
Rekor RekorOptions
Fulcio FulcioOptions
OIDC OIDCOptions
Key string
}
var _ Interface = (*AttestOptions)(nil)
func (o *AttestOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
if err := o.Rekor.AddFlags(cmd, v); err != nil {
return err
}
if err := o.Fulcio.AddFlags(cmd, v); err != nil {
return err
}
if err := o.OIDC.AddFlags(cmd, v); err != nil {
return err
}
cmd.Flags().StringVarP(&o.Key, "key", "", defaultKeyFileName,
"path to the private key file to use for attestation")
cmd.Flags().StringVarP(&o.Cert, "cert", "", "",
"path to the x.509 certificate in PEM format to include in the OCI Signature")
cmd.Flags().BoolVarP(&o.NoUpload, "no-upload", "", false,
"do not upload the generated attestation")
cmd.Flags().BoolVarP(&o.Force, "force", "", false,
"skip warnings and confirmations")
cmd.Flags().BoolVarP(&o.Recursive, "recursive", "", false,
"if a multi-arch image is specified, additionally sign each discrete image")
return bindAttestationConfigOptions(cmd.Flags(), v)
func (o AttestOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
cmd.Flags().StringVarP(&o.Key, "key", "k", "", "the key to use for the attestation")
return bindAttestConfigOptions(cmd.Flags(), v)
}
func bindAttestationConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
//nolint:revive
func bindAttestConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
if err := v.BindPFlag("attest.key", flags.Lookup("key")); err != nil {
return err
}
if err := v.BindPFlag("attest.cert", flags.Lookup("cert")); err != nil {
return err
}
if err := v.BindPFlag("attest.no-upload", flags.Lookup("no-upload")); err != nil {
return err
}
if err := v.BindPFlag("attest.force", flags.Lookup("force")); err != nil {
return err
}
if err := v.BindPFlag("attest.recursive", flags.Lookup("recursive")); err != nil {
return err
}
return nil
}
-32
View File
@@ -1,32 +0,0 @@
package options
import (
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/sbom"
)
func FormatAliases(ids ...sbom.FormatID) (aliases []string) {
for _, id := range ids {
switch id {
case syft.JSONFormatID:
aliases = append(aliases, "syft-json")
case syft.TextFormatID:
aliases = append(aliases, "text")
case syft.TableFormatID:
aliases = append(aliases, "table")
case syft.SPDXJSONFormatID:
aliases = append(aliases, "spdx-json")
case syft.SPDXTagValueFormatID:
aliases = append(aliases, "spdx-tag-value")
case syft.CycloneDxXMLFormatID:
aliases = append(aliases, "cyclonedx-xml")
case syft.CycloneDxJSONFormatID:
aliases = append(aliases, "cyclonedx-json")
case syft.GitHubID:
aliases = append(aliases, "github", "github-json")
default:
aliases = append(aliases, string(id))
}
}
return aliases
}
+1
View File
@@ -31,6 +31,7 @@ func (o *FulcioOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
return bindFulcioConfigOptions(cmd.Flags(), v)
}
//nolint:revive
func bindFulcioConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
if err := v.BindPFlag("attest.fulcio-url", flags.Lookup("fulcio-url")); err != nil {
return err
+1
View File
@@ -31,6 +31,7 @@ func (o *OIDCOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
return bindOIDCConfigOptions(cmd.Flags(), v)
}
//nolint:revive
func bindOIDCConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
if err := v.BindPFlag("attest.oidc-issuer", flags.Lookup("oidc-issuer")); err != nil {
return err
+12 -3
View File
@@ -7,7 +7,7 @@ import (
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/formats"
"github.com/anchore/syft/syft/formats/table"
"github.com/anchore/syft/syft/pkg/cataloger"
"github.com/anchore/syft/syft/source"
@@ -21,6 +21,7 @@ type PackagesOptions struct {
Platform string
Exclude []string
Catalogers []string
Name string
}
var _ Interface = (*PackagesOptions)(nil)
@@ -29,8 +30,8 @@ func (o *PackagesOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
cmd.Flags().StringVarP(&o.Scope, "scope", "s", cataloger.DefaultSearchConfig().Scope.String(),
fmt.Sprintf("selection of layers to catalog, options=%v", source.AllScopes))
cmd.Flags().StringArrayVarP(&o.Output, "output", "o", FormatAliases(table.ID),
fmt.Sprintf("report output format, options=%v", FormatAliases(syft.FormatIDs()...)))
cmd.Flags().StringArrayVarP(&o.Output, "output", "o", []string{string(table.ID)},
fmt.Sprintf("report output format, options=%v", formats.AllIDs()))
cmd.Flags().StringVarP(&o.File, "file", "", "",
"file to write the default report output to (default is STDOUT)")
@@ -47,9 +48,13 @@ func (o *PackagesOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
cmd.Flags().StringArrayVarP(&o.Catalogers, "catalogers", "", nil,
"enable one or more package catalogers")
cmd.Flags().StringVarP(&o.Name, "name", "", "",
"set the name of the target being analyzed")
return bindPackageConfigOptions(cmd.Flags(), v)
}
//nolint:revive
func bindPackageConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
// Formatting & Input options //////////////////////////////////////////////
@@ -69,6 +74,10 @@ func bindPackageConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
return err
}
if err := v.BindPFlag("name", flags.Lookup("name")); err != nil {
return err
}
if err := v.BindPFlag("output", flags.Lookup("output")); err != nil {
return err
}
+1
View File
@@ -22,6 +22,7 @@ func (o *RekorOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
return bindRekorConfigOptions(cmd.Flags(), v)
}
//nolint:revive
func bindRekorConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
// TODO: config re-design
if err := v.BindPFlag("attest.rekor-url", flags.Lookup("rekor-url")); err != nil {
+1
View File
@@ -22,6 +22,7 @@ func (o *RootOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
return bindRootConfigOptions(cmd.PersistentFlags(), v)
}
//nolint:revive
func bindRootConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
if err := v.BindPFlag("config", flags.Lookup("config")); err != nil {
return err
+2 -2
View File
@@ -9,9 +9,9 @@ type VersionOptions struct {
Output string
}
var _ Interface = (*PackagesOptions)(nil)
var _ Interface = (*VersionOptions)(nil)
func (o *VersionOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
func (o *VersionOptions) AddFlags(cmd *cobra.Command, _ *viper.Viper) error {
cmd.Flags().StringVarP(&o.Output, "output", "o", "text", "format to show version information (available=[text, json])")
return nil
}
+4 -4
View File
@@ -6,7 +6,7 @@ import (
"github.com/hashicorp/go-multierror"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/formats"
"github.com/anchore/syft/syft/formats/table"
"github.com/anchore/syft/syft/formats/template"
"github.com/anchore/syft/syft/sbom"
@@ -32,7 +32,7 @@ func MakeWriter(outputs []string, defaultFile, templateFilePath string) (sbom.Wr
func parseOutputs(outputs []string, defaultFile, templateFilePath string) (out []sbom.WriterOption, errs error) {
// always should have one option -- we generally get the default of "table", but just make sure
if len(outputs) == 0 {
outputs = append(outputs, string(table.ID))
outputs = append(outputs, table.ID.String())
}
for _, name := range outputs {
@@ -52,9 +52,9 @@ func parseOutputs(outputs []string, defaultFile, templateFilePath string) (out [
file = parts[1]
}
format := syft.FormatByName(name)
format := formats.ByName(name)
if format == nil {
errs = multierror.Append(errs, fmt.Errorf(`unsupported output format "%s", supported formats are: %+v`, name, FormatAliases(syft.FormatIDs()...)))
errs = multierror.Append(errs, fmt.Errorf(`unsupported output format "%s", supported formats are: %+v`, name, formats.AllIDs()))
continue
}
+5 -3
View File
@@ -18,8 +18,10 @@ const (
{{.appName}} {{.command}} alpine:latest -o json show all possible cataloging details
{{.appName}} {{.command}} alpine:latest -o cyclonedx show a CycloneDX formatted SBOM
{{.appName}} {{.command}} alpine:latest -o cyclonedx-json show a CycloneDX JSON formatted SBOM
{{.appName}} {{.command}} alpine:latest -o spdx show a SPDX 2.2 Tag-Value formatted SBOM
{{.appName}} {{.command}} alpine:latest -o spdx-json show a SPDX 2.2 JSON formatted SBOM
{{.appName}} {{.command}} alpine:latest -o spdx show a SPDX 2.3 Tag-Value formatted SBOM
{{.appName}} {{.command}} alpine:latest -o spdx@2.2 show a SPDX 2.2 Tag-Value formatted SBOM
{{.appName}} {{.command}} alpine:latest -o spdx-json show a SPDX 2.3 JSON formatted SBOM
{{.appName}} {{.command}} alpine:latest -o spdx-json@2.2 show a SPDX 2.2 JSON formatted SBOM
{{.appName}} {{.command}} alpine:latest -vv show verbose debug information
{{.appName}} {{.command}} alpine:latest -o template -t my_format.tmpl show a SBOM formatted according to given template file
@@ -57,7 +59,7 @@ func Packages(v *viper.Viper, app *config.Application, ro *options.RootOptions,
}),
Args: func(cmd *cobra.Command, args []string) error {
if err := app.LoadAllValues(v, ro.Config); err != nil {
return fmt.Errorf("invalid application config: %v", err)
return fmt.Errorf("invalid application config: %w", err)
}
// configure logging for command
newLogWrapper(app)
+4 -4
View File
@@ -23,8 +23,8 @@ import (
"github.com/anchore/syft/syft/source"
)
func Run(ctx context.Context, app *config.Application, args []string) error {
err := validateOutputOptions(app)
func Run(_ context.Context, app *config.Application, args []string) error {
err := ValidateOutputOptions(app)
if err != nil {
return err
}
@@ -42,7 +42,7 @@ func Run(ctx context.Context, app *config.Application, args []string) error {
// could be an image or a directory, with or without a scheme
userInput := args[0]
si, err := source.ParseInput(userInput, app.Platform, true)
si, err := source.ParseInputWithName(userInput, app.Platform, app.Name, app.DefaultImagePullSource)
if err != nil {
return fmt.Errorf("could not generate source input for packages command: %w", err)
}
@@ -134,7 +134,7 @@ func MergeRelationships(cs ...<-chan artifact.Relationship) (relationships []art
return relationships
}
func validateOutputOptions(app *config.Application) error {
func ValidateOutputOptions(app *config.Application) error {
var usesTemplateOutput bool
for _, o := range app.Outputs {
if o == template.ID.String() {
+1 -1
View File
@@ -28,7 +28,7 @@ func PowerUser(v *viper.Viper, app *config.Application, ro *options.RootOptions)
}),
Args: func(cmd *cobra.Command, args []string) error {
if err := app.LoadAllValues(v, ro.Config); err != nil {
return fmt.Errorf("invalid application config: %v", err)
return fmt.Errorf("invalid application config: %w", err)
}
// configure logging for command
newLogWrapper(app)
+4 -3
View File
@@ -26,9 +26,10 @@ import (
"github.com/anchore/syft/syft/source"
)
func Run(ctx context.Context, app *config.Application, args []string) error {
func Run(_ context.Context, app *config.Application, args []string) error {
f := syftjson.Format()
writer, err := sbom.NewWriter(sbom.WriterOption{
Format: syftjson.Format(),
Format: f,
Path: app.File,
})
if err != nil {
@@ -46,7 +47,7 @@ func Run(ctx context.Context, app *config.Application, args []string) error {
}()
userInput := args[0]
si, err := source.ParseInput(userInput, app.Platform, true)
si, err := source.ParseInputWithName(userInput, app.Platform, app.Name, app.DefaultImagePullSource)
if err != nil {
return fmt.Errorf("could not generate source input for packages command: %w", err)
}
+1 -1
View File
@@ -15,7 +15,7 @@ import (
"github.com/anchore/syft/internal/version"
)
func Version(v *viper.Viper, app *config.Application) *cobra.Command {
func Version(v *viper.Viper, _ *config.Application) *cobra.Command {
o := &options.VersionOptions{}
cmd := &cobra.Command{
Use: "version",
+58 -239
View File
@@ -1,26 +1,24 @@
module github.com/anchore/syft
go 1.18
go 1.19
require (
github.com/CycloneDX/cyclonedx-go v0.5.2
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/acobaugh/osrelease v0.1.0
github.com/adrg/xdg v0.3.3
github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074
github.com/adrg/xdg v0.4.0
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7
github.com/bmatcuk/doublestar/v4 v4.0.2
github.com/dustin/go-humanize v1.0.0
github.com/facebookincubator/nvdtools v0.1.4
github.com/go-test/deep v1.0.8
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501
github.com/bmatcuk/doublestar/v4 v4.6.0
github.com/dustin/go-humanize v1.0.1
github.com/facebookincubator/nvdtools v0.1.5
github.com/go-test/deep v1.1.0
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.0
github.com/gookit/color v1.4.2
github.com/gookit/color v1.5.3
github.com/hashicorp/go-multierror v1.1.1
github.com/jinzhu/copier v0.3.2
github.com/jinzhu/copier v0.3.5
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mholt/archiver/v3 v3.5.1
github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5
@@ -31,287 +29,112 @@ require (
github.com/pelletier/go-toml v1.9.5
// 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/sergi/go-diff v1.3.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.6.0
github.com/spdx/tools-golang v0.5.0
github.com/spf13/afero v1.9.5
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.13.0
github.com/stretchr/testify v1.8.0
github.com/vifraa/gopom v0.1.0
github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.2
github.com/vifraa/gopom v0.2.1
github.com/wagoodman/go-partybus v0.0.0-20210627031916-db1f5573bbc5
github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240
github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb
github.com/xeipuuv/gojsonschema v1.2.0
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458
golang.org/x/term v0.0.0-20220919170432-7a66f970e087
golang.org/x/mod v0.9.0
golang.org/x/net v0.8.0
golang.org/x/term v0.6.0
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/Masterminds/sprig/v3 v3.2.2
github.com/CycloneDX/cyclonedx-go v0.7.1-0.20221222100750-41a1ac565cce
github.com/Masterminds/sprig/v3 v3.2.3
github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8
github.com/anchore/stereoscope v0.0.0-20221006201143-d24c9d626b33
github.com/docker/docker v20.10.17+incompatible
github.com/google/go-containerregistry v0.11.0
github.com/in-toto/in-toto-golang v0.4.1-0.20221018183522-731d0640b65f
github.com/anchore/stereoscope v0.0.0-20230323161519-d7551b7f46f5
github.com/docker/docker v23.0.2+incompatible
github.com/google/go-containerregistry v0.14.0
github.com/google/licensecheck v0.3.1
github.com/invopop/jsonschema v0.7.0
github.com/knqyf263/go-rpmdb v0.0.0-20221030135625-4082a22221ce
github.com/opencontainers/go-digest v1.0.0
github.com/sassoftware/go-rpmutils v0.2.0
github.com/sigstore/cosign v1.13.1
github.com/sigstore/rekor v0.12.1-0.20220915152154-4bb6f441c1b2
github.com/sigstore/sigstore v1.4.4
github.com/vbatts/go-mtree v0.5.0
github.com/vbatts/go-mtree v0.5.3
golang.org/x/exp v0.0.0-20230202163644-54bba9f4231b
gopkg.in/yaml.v3 v3.0.1
)
require (
bitbucket.org/creachadair/shell v0.0.7 // indirect
cloud.google.com/go/compute v1.10.0 // indirect
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // 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.28 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.21 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // 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/DataDog/zstd v1.4.5 // 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/ThalesIgnite/crypto11 v1.2.5 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect
github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect
github.com/alibabacloud-go/darabonba-openapi v0.1.18 // indirect
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 // indirect
github.com/alibabacloud-go/endpoint-util v1.1.1 // indirect
github.com/alibabacloud-go/openapi-util v0.0.11 // indirect
github.com/alibabacloud-go/tea v1.1.18 // indirect
github.com/alibabacloud-go/tea-utils v1.4.4 // indirect
github.com/alibabacloud-go/tea-xml v1.1.2 // indirect
github.com/aliyun/credentials-go v1.2.3 // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/aws/aws-sdk-go-v2 v1.16.16 // indirect
github.com/aws/aws-sdk-go-v2/config v1.17.8 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.12.21 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24 // 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.17 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.23 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.16.19 // indirect
github.com/aws/smithy-go v1.13.3 // indirect
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220517224237-e6f29200ae04 // indirect
github.com/benbjohnson/clock v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20220119192733-fe33c00cee21 // indirect
github.com/clbanning/mxj/v2 v2.5.6 // indirect
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
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.6.8 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.12.0 // indirect
github.com/coreos/go-oidc/v3 v3.4.0 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20210823021906-dc406ceaf94b // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/containerd/containerd v1.6.18 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/docker/cli v20.10.17+incompatible // indirect
github.com/docker/cli v23.0.1+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker-credential-helpers v0.6.4 // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/fullstorydev/grpcurl v1.8.7 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.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.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.2 // indirect
github.com/go-openapi/runtime v0.24.2 // 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.22.3 // indirect
github.com/go-openapi/validate v0.22.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.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
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/certificate-transparency-go v1.1.3 // indirect
github.com/google/go-github/v45 v45.2.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/trillian v1.5.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // 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/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b // indirect
github.com/jhump/protoreflect v1.13.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/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/compress v1.16.0 // 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-20220929215747-76583552c2be // 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
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mozillazg/docker-credential-acr-helper v0.3.0 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
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.5 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect
github.com/prometheus/client_model v0.2.0 // 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
github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/sigstore/fulcio v0.6.0 // 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
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spiffe/go-spiffe/v2 v2.1.1 // indirect
github.com/stretchr/objx v0.4.0 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/sylabs/sif/v2 v2.8.1 // indirect
github.com/sylabs/squashfs v0.6.1 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 // indirect
github.com/thales-e-security/pool v0.0.2 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 // indirect
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
github.com/tjfoc/gmsm v1.3.2 // indirect
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
github.com/transparency-dev/merkle v0.0.1 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/urfave/cli v1.22.7 // indirect
github.com/vbatts/tar-split v0.11.2 // 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
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
github.com/zeebo/errs v1.2.2 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.etcd.io/etcd/api/v3 v3.6.0-alpha.0 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.0-alpha.0 // indirect
go.etcd.io/etcd/client/v2 v2.306.0-alpha.0 // indirect
go.etcd.io/etcd/client/v3 v3.6.0-alpha.0 // indirect
go.etcd.io/etcd/etcdctl/v3 v3.6.0-alpha.0 // indirect
go.etcd.io/etcd/etcdutl/v3 v3.6.0-alpha.0 // indirect
go.etcd.io/etcd/pkg/v3 v3.6.0-alpha.0 // indirect
go.etcd.io/etcd/raft/v3 v3.6.0-alpha.0 // indirect
go.etcd.io/etcd/server/v3 v3.6.0-alpha.0 // indirect
go.etcd.io/etcd/tests/v3 v3.6.0-alpha.0 // indirect
go.etcd.io/etcd/v3 v3.6.0-alpha.0 // indirect
go.mongodb.org/mongo-driver v1.10.0 // indirect
go.opencensus.io v0.23.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 // indirect
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect
go.opentelemetry.io/proto/otlp v0.16.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.23.0 // indirect
golang.org/x/exp v0.0.0-20220823124025-807a23277127 // indirect
golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1 // indirect
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.12 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/tools v0.7.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.99.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e // indirect
google.golang.org/grpc v1.50.1 // 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
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect
google.golang.org/grpc v1.52.0 // indirect
google.golang.org/protobuf v1.29.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
k8s.io/api v0.23.5 // indirect
k8s.io/apimachinery v0.23.5 // indirect
k8s.io/client-go v0.23.5 // indirect
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
lukechampine.com/uint128 v1.1.1 // indirect
modernc.org/cc/v3 v3.36.0 // indirect
modernc.org/ccgo/v3 v3.16.6 // indirect
@@ -322,10 +145,6 @@ require (
modernc.org/sqlite v1.17.3 // indirect
modernc.org/strutil v1.1.1 // indirect
modernc.org/token v1.0.0 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
sigs.k8s.io/release-utils v0.7.3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
require (
@@ -333,7 +152,7 @@ require (
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect
golang.org/x/crypto v0.3.0 // indirect
)
retract (
+162 -2166
View File
File diff suppressed because it is too large Load Diff
+77 -29
View File
@@ -3,6 +3,7 @@ package config
import (
"errors"
"fmt"
"os"
"path"
"reflect"
"sort"
@@ -17,6 +18,7 @@ import (
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/pkg/cataloger"
golangCataloger "github.com/anchore/syft/syft/pkg/cataloger/golang"
)
var (
@@ -38,23 +40,27 @@ type Application struct {
ConfigPath string `yaml:"configPath,omitempty" json:"configPath" mapstructure:"config"`
Verbosity uint `yaml:"verbosity,omitempty" json:"verbosity" mapstructure:"verbosity"`
// -q, indicates to not show any status output to stderr (ETUI or logging UI)
Quiet bool `yaml:"quiet" json:"quiet" mapstructure:"quiet"`
Outputs []string `yaml:"output" json:"output" mapstructure:"output"` // -o, the format to use for output
OutputTemplatePath string `yaml:"output-template-path" json:"output-template-path" mapstructure:"output-template-path"` // -t template file to use for output
File string `yaml:"file" json:"file" mapstructure:"file"` // --file, the file to write report output to
CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not
Dev development `yaml:"dev" json:"dev" mapstructure:"dev"`
Log logging `yaml:"log" json:"log" mapstructure:"log"` // all logging-related options
Catalogers []string `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
Package pkg `yaml:"package" json:"package" mapstructure:"package"`
FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
FileClassification fileClassification `yaml:"file-classification" json:"file-classification" mapstructure:"file-classification"`
FileContents fileContents `yaml:"file-contents" json:"file-contents" mapstructure:"file-contents"`
Secrets secrets `yaml:"secrets" json:"secrets" mapstructure:"secrets"`
Registry registry `yaml:"registry" json:"registry" mapstructure:"registry"`
Exclusions []string `yaml:"exclude" json:"exclude" mapstructure:"exclude"`
Attest attest `yaml:"attest" json:"attest" mapstructure:"attest"`
Platform string `yaml:"platform" json:"platform" mapstructure:"platform"`
Quiet bool `yaml:"quiet" json:"quiet" mapstructure:"quiet"`
Outputs []string `yaml:"output" json:"output" mapstructure:"output"` // -o, the format to use for output
OutputTemplatePath string `yaml:"output-template-path" json:"output-template-path" mapstructure:"output-template-path"` // -t template file to use for output
File string `yaml:"file" json:"file" mapstructure:"file"` // --file, the file to write report output to
CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not
Dev development `yaml:"dev" json:"dev" mapstructure:"dev"`
Log logging `yaml:"log" json:"log" mapstructure:"log"` // all logging-related options
Catalogers []string `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
Package pkg `yaml:"package" json:"package" mapstructure:"package"`
Golang golang `yaml:"golang" json:"golang" mapstructure:"golang"`
Attest attest `yaml:"attest" json:"attest" mapstructure:"attest"`
FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
FileClassification fileClassification `yaml:"file-classification" json:"file-classification" mapstructure:"file-classification"`
FileContents fileContents `yaml:"file-contents" json:"file-contents" mapstructure:"file-contents"`
Secrets secrets `yaml:"secrets" json:"secrets" mapstructure:"secrets"`
Registry registry `yaml:"registry" json:"registry" mapstructure:"registry"`
Exclusions []string `yaml:"exclude" json:"exclude" mapstructure:"exclude"`
Platform string `yaml:"platform" json:"platform" mapstructure:"platform"`
Name string `yaml:"name" json:"name" mapstructure:"name"`
Parallelism int `yaml:"parallelism" json:"parallelism" mapstructure:"parallelism"` // the number of catalog workers to run in parallel
DefaultImagePullSource string `yaml:"default-image-pull-source" json:"default-image-pull-source" mapstructure:"default-image-pull-source"` // specify default image pull source
}
func (cfg Application) ToCatalogerConfig() cataloger.Config {
@@ -64,7 +70,12 @@ func (cfg Application) ToCatalogerConfig() cataloger.Config {
IncludeUnindexedArchives: cfg.Package.SearchUnindexedArchives,
Scope: cfg.Package.Cataloger.ScopeOpt,
},
Catalogers: cfg.Catalogers,
Catalogers: cfg.Catalogers,
Parallelism: cfg.Parallelism,
Golang: golangCataloger.GoCatalogerOpts{
SearchLocalModCacheLicenses: cfg.Golang.SearchLocalModCacheLicenses,
LocalModCacheDir: cfg.Golang.LocalModCacheDir,
},
}
}
@@ -74,9 +85,11 @@ func (cfg *Application) LoadAllValues(v *viper.Viper, configPath string) error {
// check if user specified config; otherwise read all possible paths
if err := loadConfig(v, configPath); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Not Found; ignore this error
log.Debug("no config file found; proceeding with defaults")
var notFound *viper.ConfigFileNotFoundError
if errors.As(err, &notFound) {
log.Debugf("no config file found, using defaults")
} else {
return fmt.Errorf("unable to load config: %w", err)
}
}
@@ -118,6 +131,12 @@ func (cfg *Application) parseConfigValues() error {
return err
}
}
if err := checkDefaultSourceValues(cfg.DefaultImagePullSource); err != nil {
return err
}
// check for valid default source options
// parse nested config options
// for each field in the configuration struct, see if the field implements the parser interface
// note: the app config is a pointer, so we need to grab the elements explicitly (to traverse the address)
@@ -179,6 +198,8 @@ func loadDefaultValues(v *viper.Viper) {
v.SetDefault("quiet", false)
v.SetDefault("check-for-app-update", true)
v.SetDefault("catalogers", nil)
v.SetDefault("parallelism", 1)
v.SetDefault("default-image-pull-source", "")
// for each field in the configuration struct, see if the field implements the defaultValueLoader interface and invoke it if it does
value := reflect.ValueOf(Application{})
@@ -202,6 +223,7 @@ func (cfg Application) String() string {
return string(appaStr)
}
// nolint:funlen
func loadConfig(v *viper.Viper, configPath string) error {
var err error
// use explicitly the given user config
@@ -217,13 +239,26 @@ func loadConfig(v *viper.Viper, configPath string) error {
// start searching for valid configs in order...
// 1. look for .<appname>.yaml (in the current directory)
confFilePath := "." + internal.ApplicationName
// TODO: Remove this before v1.0.0
// See syft #1634
v.AddConfigPath(".")
v.SetConfigName("." + internal.ApplicationName)
if err = v.ReadInConfig(); err == nil {
v.Set("config", v.ConfigFileUsed())
return nil
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
v.SetConfigName(confFilePath)
// check if config.yaml exists in the current directory
// DEPRECATED: this will be removed in v1.0.0
if _, err := os.Stat("config.yaml"); err == nil {
log.Warn("DEPRECATED: ./config.yaml as a configuration file is deprecated and will be removed as an option in v1.0.0, please rename to .syft.yaml")
}
if _, err := os.Stat(confFilePath + ".yaml"); err == nil {
if err = v.ReadInConfig(); err == nil {
v.Set("config", v.ConfigFileUsed())
return nil
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
}
}
// 2. look for .<appname>/config.yaml (in the current directory)
@@ -250,11 +285,12 @@ func loadConfig(v *viper.Viper, configPath string) error {
}
// 4. look for <appname>/config.yaml in xdg locations (starting with xdg home config dir, then moving upwards)
v.AddConfigPath(path.Join(xdg.ConfigHome, internal.ApplicationName))
v.SetConfigName("config")
configPath = path.Join(xdg.ConfigHome, internal.ApplicationName)
v.AddConfigPath(configPath)
for _, dir := range xdg.ConfigDirs {
v.AddConfigPath(path.Join(dir, internal.ApplicationName))
}
v.SetConfigName("config")
if err = v.ReadInConfig(); err == nil {
v.Set("config", v.ConfigFileUsed())
return nil
@@ -263,3 +299,15 @@ func loadConfig(v *viper.Viper, configPath string) error {
}
return nil
}
var validDefaultSourceValues = []string{"registry", "docker", "podman", ""}
func checkDefaultSourceValues(source string) error {
validValues := internal.NewStringSet(validDefaultSourceValues...)
if !validValues.Contains(source) {
validValuesString := strings.Join(validDefaultSourceValues, ", ")
return fmt.Errorf("%s is not a valid default source; please use one of the following: %s''", source, validValuesString)
}
return nil
}
+129
View File
@@ -0,0 +1,129 @@
package config
import (
"fmt"
"os"
"path"
"testing"
"github.com/adrg/xdg"
"github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TODO: set negative case when config.yaml is no longer a valid option
func TestApplicationConfig(t *testing.T) {
// disable homedir package cache for testing
originalCacheOpt := homedir.DisableCache
homedir.DisableCache = true
t.Cleanup(func() {
homedir.DisableCache = originalCacheOpt
})
// ensure we have no side effects for xdg package for future tests
originalXDG := os.Getenv("XDG_CONFIG_HOME")
t.Cleanup(func() {
// note: we're not using t.Setenv since the effect we're trying to eliminate is within the xdg package
require.NoError(t, os.Setenv("XDG_CONFIG_HOME", originalXDG))
xdg.Reload()
})
// config is picked up at desired configuration paths
// VALID: .syft.yaml, .syft/config.yaml, ~/.syft.yaml, <XDG_CONFIG_HOME>/syft/config.yaml
// DEPRECATED: config.yaml is currently supported by
tests := []struct {
name string
setup func(t *testing.T) string
assertions func(t *testing.T, app *Application)
cleanup func()
}{
{
name: "explicit config",
setup: func(t *testing.T) string {
return "./test-fixtures/.syft.yaml"
}, // no-op for explicit config
assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-explicit-config", app.File)
},
},
{
name: "current working directory named config",
setup: func(t *testing.T) string {
err := os.Chdir("./test-fixtures/config-wd-file") // change application cwd to test-fixtures
require.NoError(t, err)
return ""
},
assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-wd-named-config", app.File)
},
},
{
name: "current working directory syft dir config",
setup: func(t *testing.T) string {
err := os.Chdir("./test-fixtures/config-dir-test") // change application cwd to test-fixtures
require.NoError(t, err)
return ""
},
assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-dir-config", app.File)
},
},
{
name: "home directory file config",
setup: func(t *testing.T) string {
// Because Setenv affects the whole process, it cannot be used in parallel tests or
// tests with parallel ancestors: see separate XDG test for consequence of this
t.Setenv("HOME", "./test-fixtures/config-home-test/config-file")
return ""
},
assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-home-config", app.File)
},
},
{
name: "XDG file config",
setup: func(t *testing.T) string {
wd, err := os.Getwd()
require.NoError(t, err)
configDir := path.Join(wd, "./test-fixtures/config-home-test") // set HOME to testdata
// note: this explicitly has multiple XDG paths, make certain we use the first VALID one (not the first one)
t.Setenv("XDG_CONFIG_DIRS", fmt.Sprintf("/another/foo/bar:%s", configDir))
xdg.Reload()
return ""
},
assertions: func(t *testing.T, app *Application) {
assert.Equal(t, "test-home-XDG-config", app.File)
},
cleanup: func() {
require.NoError(t, os.Unsetenv("XDG_CONFIG_DIRS"))
xdg.Reload()
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.cleanup != nil {
t.Cleanup(test.cleanup)
}
wd, err := os.Getwd()
require.NoError(t, err)
defer os.Chdir(wd) // reset working directory after test
application := &Application{}
viperInstance := viper.New()
// this will override home in case you are running this test locally and DO have a syft config
// in your home directory... now it will be ignored. Same for XDG_CONFIG_DIRS.
t.Setenv("HOME", "/foo/bar")
t.Setenv("XDG_CONFIG_DIRS", "/foo/bar")
xdg.Reload()
configPath := test.setup(t)
err = application.LoadAllValues(viperInstance, configPath)
require.NoError(t, err)
test.assertions(t, application)
})
}
}
+4 -46
View File
@@ -1,56 +1,14 @@
package config
import (
"fmt"
"os"
import "github.com/spf13/viper"
"github.com/mitchellh/go-homedir"
"github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/spf13/viper"
)
// IMPORTANT: do not show the password in any YAML/JSON output (sensitive information)
type attest struct {
KeyRef string `yaml:"key" json:"key" mapstructure:"key"` // same as --key, file path to the private key
Cert string `yaml:"cert" json:"cert" mapstructure:"cert"`
NoUpload bool `yaml:"no_upload" json:"noUpload" mapstructure:"no_upload"`
Force bool `yaml:"force" json:"force" mapstructure:"force"`
Recursive bool `yaml:"recursive" json:"recursive" mapstructure:"recursive"`
Replace bool `yaml:"replace" json:"replace" mapstructure:"replace"`
Password string `yaml:"-" json:"-" mapstructure:"password"` // password for the private key
FulcioURL string `yaml:"fulcio_url" json:"fulcioUrl" mapstructure:"fulcio_url"`
FulcioIdentityToken string `yaml:"fulcio_identity_token" json:"fulcio_identity_token" mapstructure:"fulcio_identity_token"`
InsecureSkipFulcioVerify bool `yaml:"insecure_skip_verify" json:"insecure_skip_verify" mapstructure:"insecure_skip_verify"`
RekorURL string `yaml:"rekor_url" json:"rekorUrl" mapstructure:"rekor_url"`
OIDCIssuer string `yaml:"oidc_issuer" json:"oidcIssuer" mapstructure:"oidc_issuer"`
OIDCClientID string `yaml:"oidc_client_id" json:"oidcClientId" mapstructure:"oidc_client_id"`
OIDCRedirectURL string `yaml:"oidc_redirect_url" json:"OIDCRedirectURL" mapstructure:"oidc_redirect_url"`
}
func (cfg *attest) parseConfigValues() error {
if cfg.KeyRef != "" {
expandedPath, err := homedir.Expand(cfg.KeyRef)
if err != nil {
return fmt.Errorf("unable to expand key path=%q: %w", cfg.KeyRef, err)
}
cfg.KeyRef = expandedPath
}
if cfg.Password == "" {
// we allow for configuration via syft config/env vars and additionally interop with known cosign config env vars
if pw, ok := os.LookupEnv("COSIGN_PASSWORD"); ok {
cfg.Password = pw
}
}
return nil
// IMPORTANT: do not show the attestation key/password in any YAML/JSON output (sensitive information)
Key string `yaml:"-" json:"-" mapstructure:"key"`
Password string `yaml:"-" json:"-" mapstructure:"password"`
}
func (cfg attest) loadDefaultValues(v *viper.Viper) {
v.SetDefault("attest.key", "")
v.SetDefault("attest.password", "")
v.SetDefault("attest.fulcio_url", options.DefaultFulcioURL)
v.SetDefault("attest.rekor_url", options.DefaultRekorURL)
v.SetDefault("attest.oidc_issuer", options.DefaultOIDCIssuerURL)
v.SetDefault("attest.oidc_client_id", "sigstore")
}
+13
View File
@@ -0,0 +1,13 @@
package config
import "github.com/spf13/viper"
type golang struct {
SearchLocalModCacheLicenses bool `json:"search-local-mod-cache-licenses" yaml:"search-local-mod-cache-licenses" mapstructure:"search-local-mod-cache-licenses"`
LocalModCacheDir string `json:"local-mod-cache-dir" yaml:"local-mod-cache-dir" mapstructure:"local-mod-cache-dir"`
}
func (cfg golang) loadDefaultValues(v *viper.Viper) {
v.SetDefault("golang.search-local-mod-cache-licenses", false)
v.SetDefault("golang.local-mod-cache-dir", "")
}
+7
View File
@@ -0,0 +1,7 @@
# same as --file; write output report to a file (default is to write to stdout)
file: "test-explicit-config"
package:
cataloger:
scope: "squashed"
# same as --scope; limit the scope of the cataloger to only the specified types
@@ -0,0 +1,5 @@
# same as --file; write output report to a file (default is to write to stdout)
file: "test-dir-config"
package:
cataloger:
scope: "squashed"
@@ -0,0 +1,5 @@
# same as --file; write output report to a file (default is to write to stdout)
file: "test-home-config"
package:
cataloger:
scope: "squashed"
@@ -0,0 +1,5 @@
# same as --file; write output report to a file (default is to write to stdout)
file: "test-home-XDG-config"
package:
cataloger:
scope: "squashed"
@@ -0,0 +1,5 @@
# same as --file; write output report to a file (default is to write to stdout)
file: "test-wd-named-config"
package:
cataloger:
scope: "squashed"
+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 = "4.1.0"
JSONSchemaVersion = "7.1.1"
)
+6 -5
View File
@@ -1,6 +1,7 @@
package internal
import (
"errors"
"fmt"
"io"
"os"
@@ -26,14 +27,14 @@ func (e ErrPath) Error() string {
}
func IsErrPath(err error) bool {
_, ok := err.(ErrPath)
return ok
var pathErr ErrPath
return errors.As(err, &pathErr)
}
func IsErrPathPermission(err error) bool {
pathErr, ok := err.(ErrPath)
if ok {
var pathErr ErrPath
if errors.As(err, &pathErr) {
return os.IsPermission(pathErr.Err)
}
return ok
return false
}
+1 -4
View File
@@ -161,10 +161,7 @@ func UnzipToDir(archivePath, targetDir string) error {
return err
}
if err = extractSingleFile(file, joinedPath, archivePath); err != nil {
return err
}
return nil
return extractSingleFile(file, joinedPath, archivePath)
}
return TraverseFilesInZip(archivePath, visitor)
+1 -3
View File
@@ -106,7 +106,7 @@ func findArchiveStartOffset(r io.ReaderAt, size int64) (startOfArchive uint64, e
bLen = size
}
buf = make([]byte, int(bLen))
if _, err := r.ReadAt(buf, size-bLen); err != nil && err != io.EOF {
if _, err := r.ReadAt(buf, size-bLen); err != nil && !errors.Is(err, io.EOF) {
return 0, err
}
if p := findSignatureInBlock(buf); p >= 0 {
@@ -146,9 +146,7 @@ func findArchiveStartOffset(r io.ReaderAt, size int64) (startOfArchive uint64, e
if err != nil {
return 0, err
}
startOfArchive = 0 // Prefixed data not supported
}
startOfArchive = uint64(directoryEndOffset) - d.directorySize - d.directoryOffset
// Make sure directoryOffset points to somewhere in our file.
+53
View File
@@ -0,0 +1,53 @@
package licenses
import "github.com/anchore/syft/internal"
// all of these taken from https://github.com/golang/pkgsite/blob/8996ff632abee854aef1b764ca0501f262f8f523/internal/licenses/licenses.go#L338
// which unfortunately is not exported. But fortunately is under BSD-style license.
var (
FileNames = []string{
"COPYING",
"COPYING.md",
"COPYING.markdown",
"COPYING.txt",
"LICENCE",
"LICENCE.md",
"LICENCE.markdown",
"LICENCE.txt",
"LICENSE",
"LICENSE.md",
"LICENSE.markdown",
"LICENSE.txt",
"LICENSE-2.0.txt",
"LICENCE-2.0.txt",
"LICENSE-APACHE",
"LICENCE-APACHE",
"LICENSE-APACHE-2.0.txt",
"LICENCE-APACHE-2.0.txt",
"LICENSE-MIT",
"LICENCE-MIT",
"LICENSE.MIT",
"LICENCE.MIT",
"LICENSE.code",
"LICENCE.code",
"LICENSE.docs",
"LICENCE.docs",
"LICENSE.rst",
"LICENCE.rst",
"MIT-LICENSE",
"MIT-LICENCE",
"MIT-LICENSE.md",
"MIT-LICENCE.md",
"MIT-LICENSE.markdown",
"MIT-LICENCE.markdown",
"MIT-LICENSE.txt",
"MIT-LICENCE.txt",
"MIT_LICENSE",
"MIT_LICENCE",
"UNLICENSE",
"UNLICENCE",
}
FileNameSet = internal.NewStringSet(FileNames...)
)
+33
View File
@@ -0,0 +1,33 @@
package licenses
import (
"io"
"github.com/google/licensecheck"
"golang.org/x/exp/slices"
)
const (
coverageThreshold = 75
unknownLicenseType = "UNKNOWN"
)
// Parse scans the contents of a license file to attempt to determine the type of license it is
func Parse(reader io.Reader) (licenses []string, err error) {
contents, err := io.ReadAll(reader)
if err != nil {
return nil, err
}
cov := licensecheck.Scan(contents)
if cov.Percent < float64(coverageThreshold) {
licenses = append(licenses, unknownLicenseType)
}
for _, m := range cov.Match {
if slices.Contains(licenses, m.ID) {
continue
}
licenses = append(licenses, m.ID)
}
return
}
@@ -11,8 +11,6 @@ import (
"strings"
"text/template"
"time"
"github.com/scylladb/go-set/strset"
)
// This program generates license_list.go.
@@ -35,7 +33,7 @@ var licenseIDs = map[string]string{
}
`))
var versionMatch = regexp.MustCompile(`-([0-9]+)\.?([0-9]+)?\.?([0-9]+)?\.?`)
var versionMatch = regexp.MustCompile(`([0-9]+)\.?([0-9]+)?\.?([0-9]+)?\.?`)
func main() {
if err := run(); err != nil {
@@ -47,12 +45,11 @@ func main() {
func run() error {
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("unable to get licenses list: %+v", err)
return fmt.Errorf("unable to get licenses list: %w", err)
}
var result LicenseList
if err = json.NewDecoder(resp.Body).Decode(&result); err != nil {
return fmt.Errorf("unable to decode license list: %+v", err)
return fmt.Errorf("unable to decode license list: %w", err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
@@ -62,7 +59,7 @@ func run() error {
f, err := os.Create(source)
if err != nil {
return fmt.Errorf("unable to create %q: %+v", source, err)
return fmt.Errorf("unable to create %q: %w", source, err)
}
defer func() {
if err := f.Close(); err != nil {
@@ -85,7 +82,7 @@ func run() error {
})
if err != nil {
return fmt.Errorf("unable to generate template: %+v", err)
return fmt.Errorf("unable to generate template: %w", err)
}
return nil
}
@@ -103,58 +100,59 @@ func run() error {
// The third pass is for overwriting deprecated licenses with replacements, for example GPL-2.0+ is deprecated
// and now maps to GPL-2.0-or-later.
func processSPDXLicense(result LicenseList) map[string]string {
// first pass build map
var licenseIDs = make(map[string]string)
for _, l := range result.Licenses {
cleanID := strings.ToLower(l.ID)
if _, exists := licenseIDs[cleanID]; exists {
log.Fatalf("duplicate license ID found: %q", cleanID)
}
licenseIDs[cleanID] = l.ID
}
// The order of variations/permutations of a license ID matters because of we how shuffle its digits,
// that is because the permutation code can generate the same value for two difference licenses,
// for example: The licenses `ABC-1.0` and `ABC-1.1` can both map to `ABC-1`,
// so we need to guarantee the order they are created to avoid mapping them wrongly. So we use a sorted list.
// To overwrite deprecated licenses during the first pass we would later on rely on map order,
// [which in go is not consistent by design](https://stackoverflow.com/a/55925880).
// The order of variations/permutations of a license ID matter.
// The permutation code can generate the same value for two difference licenses,
// for example: The licenses `ABC-1.0` and `ABC-1.1` can both map to `ABC1`,
// we need to guarantee the order they are created to avoid mapping them incorrectly.
// To do this we use a sorted list.
sort.Slice(result.Licenses, func(i, j int) bool {
return result.Licenses[i].ID < result.Licenses[j].ID
})
// second pass to build exceptions and replacements
replaced := strset.New()
// keys are simplified by removing dashes and lowercasing ID
// this is so license declarations in the wild like: LGPL3 LGPL-3 lgpl3 and lgpl-3 can all match
licenseIDs := make(map[string]string)
for _, l := range result.Licenses {
var multipleID []string
cleanID := strings.ToLower(l.ID)
// licensePerms includes the cleanID in return slice
cleanID := cleanLicenseID(l.ID)
licensePerms := buildLicenseIDPermutations(cleanID)
var replacement *License
// if license is deprecated, find its replacement and add to licenseIDs
if l.Deprecated {
replacement = result.findReplacementLicense(l)
idToMap := l.ID
replacement := result.findReplacementLicense(l)
if replacement != nil {
licenseIDs[cleanID] = replacement.ID
idToMap = replacement.ID
}
// it's important to use the original licensePerms here so that the deprecated license
// can now point to the new correct license
for _, id := range licensePerms {
if _, exists := licenseIDs[id]; exists {
// can be used to debug duplicate license permutations and confirm that examples like GPL1
// do not point to GPL-1.1
// log.Println("duplicate license list permutation found when mapping deprecated license to replacement")
// log.Printf("already have key: %q for SPDX ID: %q; attempted to map replacement ID: %q for deprecated ID: %q\n", id, value, replacement.ID, l.ID)
continue
}
licenseIDs[id] = idToMap
}
}
multipleID = append(multipleID, buildLicensePermutations(cleanID)...)
for _, id := range multipleID {
// don't make replacements for IDs that have already been replaced. Since we have a sorted license list
// the earliest replacement is correct (any future replacements are not.
// e.g. replace lgpl-2 with LGPL-2.1-only is wrong, but with LGPL-2.0-only is correct)
if replacement == nil || replaced.Has(id) {
if _, exists := licenseIDs[id]; !exists {
licenseIDs[id] = l.ID
}
} else {
// a useful debugging line during builds
log.Printf("replacing %s with %s\n", id, replacement.ID)
licenseIDs[id] = replacement.ID
replaced.Add(id)
// if license is not deprecated, add all permutations to licenseIDs
for _, id := range licensePerms {
if _, exists := licenseIDs[id]; exists {
// log.Println("found duplicate license permutation key for non deprecated license")
// log.Printf("already have key: %q for SPDX ID: %q; tried to insert as SPDX ID:%q\n", id, value, l.ID)
continue
}
licenseIDs[id] = l.ID
}
}
return licenseIDs
}
func cleanLicenseID(id string) string {
cleanID := strings.ToLower(id)
return strings.ReplaceAll(cleanID, "-", "")
}
File diff suppressed because it is too large Load Diff
+55 -53
View File
@@ -20,51 +20,7 @@ type License struct {
SeeAlso []string `json:"seeAlso"`
}
func (l License) canReplace(other License) bool {
if l.Deprecated {
return false
}
// We want to replace deprecated licenses with non-deprecated counterparts
// For more information, see: https://github.com/spdx/license-list-XML/issues/1676
if other.Deprecated {
switch {
case strings.ReplaceAll(l.ID, "-only", "") == other.ID:
return true
case strings.ReplaceAll(l.ID, "-or-later", "+") == other.ID:
return true
case l.ID == "BSD-2-Clause" && other.ID == "BSD-2-Clause-NetBSD":
return true
case l.ID == "BSD-2-Clause-Views" && other.ID == "BSD-2-Clause-FreeBSD":
return true
case l.ID == "bzip2-1.0.6" && other.ID == "bzip2-1.0.5":
return true
case l.ID == "SMLNJ" && other.ID == "StandardML-NJ":
return true
}
}
if l.Name != other.Name {
return false
}
if l.OSIApproved != other.OSIApproved {
return false
}
if len(l.SeeAlso) != len(other.SeeAlso) {
return false
}
for i, sa := range l.SeeAlso {
if sa != other.SeeAlso[i] {
return false
}
}
return l.ID == other.ID
}
// findReplacementLicense returns a replacement license for a deprecated license
func (ll LicenseList) findReplacementLicense(deprecated License) *License {
for _, l := range ll.Licenses {
if l.canReplace(deprecated) {
@@ -75,16 +31,62 @@ func (ll LicenseList) findReplacementLicense(deprecated License) *License {
return nil
}
func buildLicensePermutations(license string) (perms []string) {
lv := findLicenseVersion(license)
vp := versionPermutations(lv)
version := strings.Join(lv, ".")
for _, p := range vp {
perms = append(perms, strings.Replace(license, version, p, 1))
func (l License) canReplace(deprecated License) bool {
// don't replace a license with a deprecated license
if l.Deprecated {
return false
}
return perms
// We want to replace deprecated licenses with non-deprecated counterparts
// For more information, see: https://github.com/spdx/license-list-XML/issues/1676
switch {
case strings.ReplaceAll(l.ID, "-only", "") == deprecated.ID:
return true
case strings.ReplaceAll(l.ID, "-or-later", "+") == deprecated.ID:
return true
case l.ID == "BSD-2-Clause" && deprecated.ID == "BSD-2-Clause-NetBSD":
return true
case l.ID == "BSD-2-Clause-Views" && deprecated.ID == "BSD-2-Clause-FreeBSD":
return true
case l.ID == "bzip2-1.0.6" && deprecated.ID == "bzip2-1.0.5":
return true
case l.ID == "SMLNJ" && deprecated.ID == "StandardML-NJ":
return true
}
if l.Name != deprecated.Name {
return false
}
if l.OSIApproved != deprecated.OSIApproved {
return false
}
if len(l.SeeAlso) != len(deprecated.SeeAlso) {
return false
}
for i, sa := range l.SeeAlso {
if sa != deprecated.SeeAlso[i] {
return false
}
}
return l.ID == deprecated.ID
}
func buildLicenseIDPermutations(cleanID string) (perms []string) {
lv := findLicenseVersion(cleanID)
vp := versionPermutations(lv)
permSet := strset.New()
version := strings.Join(lv, ".")
for _, p := range vp {
permSet.Add(strings.Replace(cleanID, version, p, 1))
}
permSet.Add(cleanID)
return permSet.List()
}
func findLicenseVersion(license string) (version []string) {
+20 -23
View File
@@ -67,56 +67,57 @@ func TestLicensePermutations(t *testing.T) {
{
"GPL-1-only",
[]string{
"GPL-1-only",
"GPL-1.0-only",
"GPL-1.0.0-only",
"gpl1only",
"gpl1.0only",
"gpl1.0.0only",
},
},
{
"GPL-2",
[]string{
"GPL-2",
"GPL-2.0",
"GPL-2.0.0",
"gpl2",
"gpl2.0",
"gpl2.0.0",
},
},
{
"GPL-2.0+",
[]string{
"GPL-2+",
"GPL-2.0+",
"GPL-2.0.0+",
"gpl2+",
"gpl2.0+",
"gpl2.0.0+",
},
},
{
"GPL-3.0.0-or-later",
[]string{
"GPL-3-or-later",
"GPL-3.0-or-later",
"GPL-3.0.0-or-later",
"gpl3orlater",
"gpl3.0orlater",
"gpl3.0.0orlater",
},
},
{
"abc-1.1",
[]string{
"abc-1",
"abc-1.1",
"abc-1.1.0",
"abc1",
"abc1.1",
"abc1.1.0",
},
},
{
"oldap-2.0",
[]string{
"oldap-2",
"oldap-2.0",
"oldap-2.0.0",
"oldap2",
"oldap2.0",
"oldap2.0.0",
},
},
}
for _, test := range tests {
t.Run(test.shortName, func(t *testing.T) {
perms := buildLicensePermutations(test.shortName)
cleanID := cleanLicenseID(test.shortName)
perms := buildLicenseIDPermutations(cleanID)
assert.ElementsMatch(t, test.permutations, perms)
})
}
@@ -183,10 +184,6 @@ func TestFindLicenseVersion(t *testing.T) {
"GPL-2",
[]string{"2"},
},
{
"bzip2-1",
[]string{"1"},
},
{
"php-3.01",
[]string{"3", "01"},
File diff suppressed because it is too large Load Diff
+20 -3
View File
@@ -12,9 +12,26 @@ import (
// EX: gpl-2.0.0-only ---> GPL-2.0-only
// See the debian link for more details on the spdx license differences
const (
LicenseRefPrefix = "LicenseRef-" // prefix for non-standard licenses
)
//go:generate go run ./generate
func ID(id string) (string, bool) {
value, exists := licenseIDs[strings.ToLower(id)]
return value, exists
// ID returns the canonical license ID for the given license ID
// Note: this function is only concerned with returning a best match of an SPDX license ID
// SPDX Expressions will be handled by a parent package which will call this function
func ID(id string) (value string, exists bool) {
// first look for a canonical license
if value, exists := licenseIDs[cleanLicenseID(id)]; exists {
return value, exists
}
// we did not find, so treat it as a separate license
return "", false
}
func cleanLicenseID(id string) string {
id = strings.TrimSpace(id)
id = strings.ToLower(id)
return strings.ReplaceAll(id, "-", "")
}
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -9,8 +9,8 @@ import (
func TestLicenceListIDs(t *testing.T) {
// do a sanity check on the generated data
assert.Equal(t, "0BSD", licenseIDs["0bsd"])
assert.Equal(t, "ZPL-2.1", licenseIDs["zpl-2.1"])
assert.Equal(t, "GPL-2.0-only", licenseIDs["gpl-2"])
assert.Equal(t, "GPL-2.0-or-later", licenseIDs["gpl-2+"])
assert.Equal(t, "ZPL-2.1", licenseIDs["zpl2.1"])
assert.Equal(t, "GPL-2.0-only", licenseIDs["gpl2"])
assert.Equal(t, "GPL-2.0-or-later", licenseIDs["gpl2+"])
assert.NotEmpty(t, Version)
}
+34 -9
View File
@@ -6,55 +6,80 @@ import (
"github.com/stretchr/testify/assert"
)
func TestIDParse(t *testing.T) {
func TestSPDXIDRecognition(t *testing.T) {
var tests = []struct {
shortName string
spdx string
id string
found bool
}{
{
"GPL-1-only",
"GPL-1.0-only",
true,
},
{
"gpl1",
"GPL-1.0-only",
true,
},
{
"gpl-1",
"GPL-1.0-only",
true,
},
{
"GPL-2",
"GPL-2.0-only",
true,
},
{
"GPL-2+",
"GPL-2.0-or-later",
true,
},
{
"GPL-3.0.0-or-later",
"GPL-3.0-or-later",
true,
},
{
"GPL-3-with-autoconf-exception",
"GPL-3.0-with-autoconf-exception",
true,
},
{
"CC-by-nc-3-de",
"CC-BY-NC-3.0-DE",
true,
},
// the below few cases are NOT expected, however, seem unavoidable given the current approach
{
"w3c-20150513.0.0",
"W3C-20150513",
},
{
"spencer-86.0.0",
"Spencer-86",
true,
},
{
"unicode-dfs-2015.0.0",
"Unicode-DFS-2015",
true,
},
{
"Unknown",
"",
false,
},
{
" ",
"",
false,
},
}
for _, test := range tests {
t.Run(test.shortName, func(t *testing.T) {
got, exists := ID(test.shortName)
assert.True(t, exists)
assert.Equal(t, test.spdx, got)
value, exists := ID(test.shortName)
assert.Equal(t, test.found, exists)
assert.Equal(t, test.id, value)
})
}
}
+7
View File
@@ -28,3 +28,10 @@ func StringInSlice(a string, list []string) bool {
}
return false
}
func SplitAny(s string, seps string) []string {
splitter := func(r rune) bool {
return strings.ContainsRune(seps, r)
}
return strings.FieldsFunc(s, splitter)
}
+34
View File
@@ -104,3 +104,37 @@ func TestTruncateMiddleEllipsis(t *testing.T) {
})
}
}
func TestSplitAny(t *testing.T) {
tests := []struct {
name string
input string
fields string
want []string
}{
{
name: "simple",
input: "a,b,c",
fields: ",",
want: []string{"a", "b", "c"},
},
{
name: "empty",
input: "",
fields: ",",
want: []string{},
},
{
name: "multiple separators",
input: "a,b\nc:d",
fields: ",:\n",
want: []string{"a", "b", "c", "d"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, SplitAny(tt.input, tt.fields))
})
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ func handleExit(event partybus.Event) error {
}
if err := fn(); err != nil {
return fmt.Errorf("unable to show package catalog report: %v", err)
return fmt.Errorf("unable to show package catalog report: %w", err)
}
return nil
}
+2 -2
View File
@@ -1,5 +1,5 @@
//go:build linux || darwin
// +build linux darwin
//go:build linux || darwin || netbsd
// +build linux darwin netbsd
package ui
+2 -2
View File
@@ -1,5 +1,5 @@
//go:build linux || darwin
// +build linux darwin
//go:build linux || darwin || netbsd
// +build linux darwin netbsd
package ui
+2 -2
View File
@@ -1,5 +1,5 @@
//go:build linux || darwin
// +build linux darwin
//go:build linux || darwin || netbsd
// +build linux darwin netbsd
package ui
+32 -22
View File
@@ -10,7 +10,7 @@ import (
"sort"
"strings"
"github.com/alecthomas/jsonschema"
"github.com/invopop/jsonschema"
"github.com/anchore/syft/internal"
syftjsonModel "github.com/anchore/syft/syft/formats/syftjson/model"
@@ -27,25 +27,35 @@ can be extended to include specific package metadata struct shapes in the future
// This should represent all possible metadatas represented in the pkg.Package.Metadata field (an interface{}).
// When a new package metadata definition is created it will need to be manually added here. The variable name does
// not matter as long as it is exported.
// TODO: this should be generated from reflection of whats in the pkg package
type artifactMetadataContainer struct {
Apk pkg.ApkMetadata
Alpm pkg.AlpmMetadata
Dpkg pkg.DpkgMetadata
Gem pkg.GemMetadata
Java pkg.JavaMetadata
Npm pkg.NpmPackageJSONMetadata
Python pkg.PythonPackageMetadata
Rpm pkg.RpmMetadata
Cargo pkg.CargoPackageMetadata
Go pkg.GolangBinMetadata
Php pkg.PhpComposerJSONMetadata
Dart pkg.DartPubMetadata
Dotnet pkg.DotnetDepsMetadata
Portage pkg.PortageMetadata
Conan pkg.ConanMetadata
ConanLock pkg.ConanLockMetadata
KbPackage pkg.KbPackageMetadata
Hackage pkg.HackageMetadata
Alpm pkg.AlpmMetadata
Apk pkg.ApkMetadata
Binary pkg.BinaryMetadata
Cocopods pkg.CocoapodsMetadata
Conan pkg.ConanMetadata
ConanLock pkg.ConanLockMetadata
Dart pkg.DartPubMetadata
Dotnet pkg.DotnetDepsMetadata
Dpkg pkg.DpkgMetadata
Gem pkg.GemMetadata
GoBin pkg.GolangBinMetadata
GoMod pkg.GolangModMetadata
Hackage pkg.HackageMetadata
Java pkg.JavaMetadata
KbPackage pkg.KbPackageMetadata
Nix pkg.NixStoreMetadata
NpmPackage pkg.NpmPackageJSONMetadata
NpmPackageLock pkg.NpmPackageLockJSONMetadata
MixLock pkg.MixLockMetadata
Php pkg.PhpComposerJSONMetadata
Portage pkg.PortageMetadata
PythonPackage pkg.PythonPackageMetadata
PythonPipfilelock pkg.PythonPipfileLockMetadata
Rebar pkg.RebarLockMetadata
Rpm pkg.RpmMetadata
RustCargo pkg.CargoPackageMetadata
}
func main() {
@@ -55,7 +65,7 @@ func main() {
func build() *jsonschema.Schema {
reflector := &jsonschema.Reflector{
AllowAdditionalProperties: true,
TypeNamer: func(r reflect.Type) string {
Namer: func(r reflect.Type) string {
return strings.TrimPrefix(r.Name(), "JSON")
},
}
@@ -87,7 +97,7 @@ func build() *jsonschema.Schema {
}
for _, name := range metadataNames {
metadataTypes = append(metadataTypes, map[string]string{
"$ref": fmt.Sprintf("#/definitions/%s", name),
"$ref": fmt.Sprintf("#/$defs/%s", name),
})
}
@@ -135,7 +145,7 @@ func write(schema []byte) {
}
// the generated schema is different, bail with error :(
fmt.Printf("Cowardly refusing to overwrite existing schema (%s)!\nSee the scheam/json/README.md for how to increment\n", filename)
fmt.Printf("Cowardly refusing to overwrite existing schema (%s)!\nSee the schema/json/README.md for how to increment\n", filename)
os.Exit(1)
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-610
View File
@@ -1,610 +0,0 @@
{
"$schema" : "http://json-schema.org/draft-07/schema#",
"$id" : "http://spdx.org/rdf/terms",
"title" : "SPDX 2.2",
"type" : "object",
"properties" : {
"Document" : {
"type" : "object",
"properties" : {
"revieweds" : {
"description" : "Reviewed",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"reviewer" : {
"description" : "The name and, optionally, contact information of the person who performed the review. Values of this property must conform to the agent and tool syntax.",
"type" : "string"
},
"comment" : {
"type" : "string"
},
"reviewDate" : {
"description" : "The date and time at which the SpdxDocument was reviewed. This value must be in UTC and have 'Z' as its timezone indicator.",
"type" : "string"
}
}
}
},
"hasExtractedLicensingInfos" : {
"description" : "Indicates that a particular ExtractedLicensingInfo was defined in the subject SpdxDocument.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"seeAlsos" : {
"type" : "array",
"items" : {
"type" : "string"
}
},
"name" : {
"description" : "Identify name of this SpdxElement.",
"type" : "string"
},
"comment" : {
"type" : "string"
},
"licenseId" : {
"description" : "A human readable short form license identifier for a license. The license ID is iether on the standard license oist or the form \"LicenseRef-\"[idString] where [idString] is a unique string containing letters, numbers, \".\", \"-\" or \"+\".",
"type" : "string"
},
"extractedText" : {
"description" : "Verbatim license or licensing notice text that was discovered.",
"type" : "string"
}
},
"description" : "An ExtractedLicensingInfo represents a license or licensing notice that was found in the package. Any license text that is recognized as a license may be represented as a License rather than an ExtractedLicensingInfo."
}
},
"name" : {
"description" : "Identify name of this SpdxElement.",
"type" : "string"
},
"comment" : {
"type" : "string"
},
"spdxVersion" : {
"description" : "Provide a reference number that can be used to understand how to parse and interpret the rest of the file. It will enable both future changes to the specification and to support backward compatibility. The version number consists of a major and minor version indicator. The major field will be incremented when incompatible changes between versions are made (one or more sections are created, modified or deleted). The minor field will be incremented when backwards compatible changes are made.",
"type" : "string"
},
"annotations" : {
"description" : "Provide additional information about an SpdxElement.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"annotationDate" : {
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
"type" : "string"
},
"comment" : {
"type" : "string"
},
"annotator" : {
"description" : "This field identifies the person, organization or tool that has commented on a file, package, or the entire document.",
"type" : "string"
},
"annotationType" : {
"description" : "Type of the annotation.",
"type" : "string",
"enum" : [ "OTHER", "REVIEW" ]
}
},
"description" : "An Annotation is a comment on an SpdxItem by an agent."
}
},
"describesPackages" : {
"description" : "The describesPackage property relates an SpdxDocument to the package which it describes.",
"type" : "array",
"items" : {
"description" : "SPDX ID for Package. The describesPackage property relates an SpdxDocument to the package which it describes.",
"type" : "string"
}
},
"dataLicense" : {
"description" : "License expression for dataLicense. Compliance with the SPDX specification includes populating the SPDX fields therein with data related to such fields (\"SPDX-Metadata\"). The SPDX specification contains numerous fields where an SPDX document creator may provide relevant explanatory text in SPDX-Metadata. Without opining on the lawfulness of \"database rights\" (in jurisdictions where applicable), such explanatory text is copyrightable subject matter in most Berne Convention countries. By using the SPDX specification, or any portion hereof, you hereby agree that any copyright rights (as determined by your jurisdiction) in any SPDX-Metadata, including without limitation explanatory text, shall be subject to the terms of the Creative Commons CC0 1.0 Universal license. For SPDX-Metadata not containing any copyright rights, you hereby agree and acknowledge that the SPDX-Metadata is provided to you \"as-is\" and without any representations or warranties of any kind concerning the SPDX-Metadata, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non-infringement, or the absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.",
"type" : "string"
},
"externalDocumentRefs" : {
"description" : "Identify any external SPDX documents referenced within this SPDX document.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"externalDocumentId" : {
"description" : "externalDocumentId is a string containing letters, numbers, ., - and/or + which uniquely identifies an external document within this document.",
"type" : "string"
},
"checksum" : {
"type" : "object",
"properties" : {
"algorithm" : {
"description" : "Identifies the algorithm used to produce the subject Checksum. Currently, SHA-1 is the only supported algorithm. It is anticipated that other algorithms will be supported at a later time.",
"type" : "string",
"enum" : [ "SHA256", "SHA1", "SHA384", "MD2", "MD4", "SHA512", "MD6", "MD5", "SHA224" ]
},
"checksumValue" : {
"description" : "The checksumValue property provides a lower case hexidecimal encoded digest value produced using a specific algorithm.",
"type" : "string"
}
},
"description" : "A Checksum is value that allows the contents of a file to be authenticated. Even small changes to the content of the file will change its checksum. This class allows the results of a variety of checksum and cryptographic message digest algorithms to be represented."
},
"spdxDocument" : {
"description" : "SPDX ID for SpdxDocument. A propoerty containing an SPDX document.",
"type" : "string"
}
},
"description" : "Information about an external SPDX document reference including the checksum. This allows for verification of the external references."
}
},
"creationInfo" : {
"type" : "object",
"properties" : {
"comment" : {
"type" : "string"
},
"created" : {
"description" : "Identify when the SPDX file was originally created. The date is to be specified according to combined date and time in UTC format as specified in ISO 8601 standard. This field is distinct from the fields in section 8, which involves the addition of information during a subsequent review.",
"type" : "string"
},
"creators" : {
"description" : "Identify who (or what, in the case of a tool) created the SPDX file. If the SPDX file was created by an individual, indicate the person's name. If the SPDX file was created on behalf of a company or organization, indicate the entity name. If the SPDX file was created using a software tool, indicate the name and version for that tool. If multiple participants or tools were involved, use multiple instances of this field. Person name or organization name may be designated as “anonymous” if appropriate.",
"type" : "array",
"items" : {
"description" : "Identify who (or what, in the case of a tool) created the SPDX file. If the SPDX file was created by an individual, indicate the person's name. If the SPDX file was created on behalf of a company or organization, indicate the entity name. If the SPDX file was created using a software tool, indicate the name and version for that tool. If multiple participants or tools were involved, use multiple instances of this field. Person name or organization name may be designated as “anonymous” if appropriate.",
"type" : "string"
},
"minItems" : 1
},
"licenseListVersion" : {
"description" : "An optional field for creators of the SPDX file to provide the version of the SPDX License List used when the SPDX file was created.",
"type" : "string"
}
},
"description" : "One instance is required for each SPDX file produced. It provides the necessary information for forward and backward compatibility for processing tools."
},
"packages" : {
"description" : "Packages referenced in the SPDX document",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"attributionTexts" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include theactual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include theactual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "string"
}
},
"annotations" : {
"description" : "Provide additional information about an SpdxElement.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"annotationDate" : {
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
"type" : "string"
},
"comment" : {
"type" : "string"
},
"annotator" : {
"description" : "This field identifies the person, organization or tool that has commented on a file, package, or the entire document.",
"type" : "string"
},
"annotationType" : {
"description" : "Type of the annotation.",
"type" : "string",
"enum" : [ "OTHER", "REVIEW" ]
}
},
"description" : "An Annotation is a comment on an SpdxItem by an agent."
}
},
"supplier" : {
"description" : "The name and, optionally, contact information of the person or organization who was the immediate supplier of this package to the recipient. The supplier may be different than originator when the software has been repackaged. Values of this property must conform to the agent and tool syntax.",
"type" : "string"
},
"homepage" : {
"type" : "string"
},
"packageVerificationCode" : {
"type" : "object",
"properties" : {
"packageVerificationCodeValue" : {
"description" : "The actual package verification code as a hex encoded value.",
"type" : "string"
},
"packageVerificationCodeExcludedFiles" : {
"description" : "A file that was excluded when calculating the package verification code. This is usually a file containing SPDX data regarding the package. If a package contains more than one SPDX file all SPDX files must be excluded from the package verification code. If this is not done it would be impossible to correctly calculate the verification codes in both files.",
"type" : "array",
"items" : {
"description" : "A file that was excluded when calculating the package verification code. This is usually a file containing SPDX data regarding the package. If a package contains more than one SPDX file all SPDX files must be excluded from the package verification code. If this is not done it would be impossible to correctly calculate the verification codes in both files.",
"type" : "string"
}
}
},
"description" : "A manifest based verification code (the algorithm is defined in section 4.7 of the full specification) of the SPDX Item. This allows consumers of this data and/or database to determine if an SPDX item they have in hand is identical to the SPDX item from which the data was produced. This algorithm works even if the SPDX document is included in the SPDX item."
},
"checksums" : {
"description" : "The checksum property provides a mechanism that can be used to verify that the contents of a File or Package have not changed.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"algorithm" : {
"description" : "Identifies the algorithm used to produce the subject Checksum. Currently, SHA-1 is the only supported algorithm. It is anticipated that other algorithms will be supported at a later time.",
"type" : "string",
"enum" : [ "SHA256", "SHA1", "SHA384", "MD2", "MD4", "SHA512", "MD6", "MD5", "SHA224" ]
},
"checksumValue" : {
"description" : "The checksumValue property provides a lower case hexidecimal encoded digest value produced using a specific algorithm.",
"type" : "string"
}
},
"description" : "A Checksum is value that allows the contents of a file to be authenticated. Even small changes to the content of the file will change its checksum. This class allows the results of a variety of checksum and cryptographic message digest algorithms to be represented."
}
},
"downloadLocation" : {
"description" : "The URI at which this package is available for download. Private (i.e., not publicly reachable) URIs are acceptable as values of this property. The values http://spdx.org/rdf/terms#none and http://spdx.org/rdf/terms#noassertion may be used to specify that the package is not downloadable or that no attempt was made to determine its download location, respectively.",
"type" : "string"
},
"filesAnalyzed" : {
"description" : "Indicates whether the file content of this package has been available for or subjected to analysis when creating the SPDX document. If false indicates packages that represent metadata or URI references to a project, product, artifact, distribution or a component. If set to false, the package must not contain any files.",
"type" : "boolean"
},
"externalRefs" : {
"description" : "An External Reference allows a Package to reference an external source of additional information, metadata, enumerations, asset identifiers, or downloadable content believed to be relevant to the Package.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"comment" : {
"type" : "string"
},
"referenceCategory" : {
"description" : "Category for the external reference",
"type" : "string",
"enum" : [ "OTHER", "SECURITY", "PACKAGE_MANAGER" ]
},
"referenceLocator" : {
"description" : "The unique string with no spaces necessary to access the package-specific information, metadata, or content within the target location. The format of the locator is subject to constraints defined by the <type>.",
"type" : "string"
},
"referenceType" : {
"description" : "Type of the external reference. These are definined in an appendix in the SPDX specification.",
"type" : "string"
}
},
"description" : "An External Reference allows a Package to reference an external source of additional information, metadata, enumerations, asset identifiers, or downloadable content believed to be relevant to the Package."
}
},
"licenseComments" : {
"description" : "The licenseComments property allows the preparer of the SPDX document to describe why the licensing in spdx:licenseConcluded was chosen.",
"type" : "string"
},
"name" : {
"description" : "Identify name of this SpdxElement.",
"type" : "string"
},
"hasFiles" : {
"description" : "Indicates that a particular file belongs to a package.",
"type" : "array",
"items" : {
"description" : "SPDX ID for File. Indicates that a particular file belongs to a package.",
"type" : "string"
}
},
"comment" : {
"type" : "string"
},
"summary" : {
"description" : "Provides a short description of the package.",
"type" : "string"
},
"copyrightText" : {
"description" : "The text of copyright declarations recited in the Package or File.",
"type" : "string"
},
"originator" : {
"description" : "The name and, optionally, contact information of the person or organization that originally created the package. Values of this property must conform to the agent and tool syntax.",
"type" : "string"
},
"packageFileName" : {
"description" : "The base name of the package file name. For example, zlib-1.2.5.tar.gz.",
"type" : "string"
},
"licenseInfoFromFiles" : {
"description" : "The licensing information that was discovered directly within the package. There will be an instance of this property for each distinct value of alllicenseInfoInFile properties of all files contained in the package.",
"type" : "array",
"items" : {
"description" : "License expression for licenseInfoFromFiles. The licensing information that was discovered directly within the package. There will be an instance of this property for each distinct value of alllicenseInfoInFile properties of all files contained in the package.",
"type" : "string"
}
},
"versionInfo" : {
"description" : "Provides an indication of the version of the package that is described by this SpdxDocument.",
"type" : "string"
},
"sourceInfo" : {
"description" : "Allows the producer(s) of the SPDX document to describe how the package was acquired and/or changed from the original source.",
"type" : "string"
},
"description" : {
"description" : "Provides a detailed description of the package.",
"type" : "string"
}
}
}
},
"files" : {
"description" : "Files referenced in the SPDX document",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"fileTypes" : {
"description" : "The type of the file.",
"type" : "array",
"items" : {
"description" : "The type of the file.",
"type" : "string",
"enum" : [ "OTHER", "DOCUMENTATION", "IMAGE", "VIDEO", "ARCHIVE", "SPDX", "APPLICATION", "SOURCE", "BINARY", "TEXT", "AUDIO" ]
}
},
"attributionTexts" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include theactual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include theactual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "string"
}
},
"annotations" : {
"description" : "Provide additional information about an SpdxElement.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"annotationDate" : {
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
"type" : "string"
},
"comment" : {
"type" : "string"
},
"annotator" : {
"description" : "This field identifies the person, organization or tool that has commented on a file, package, or the entire document.",
"type" : "string"
},
"annotationType" : {
"description" : "Type of the annotation.",
"type" : "string",
"enum" : [ "OTHER", "REVIEW" ]
}
},
"description" : "An Annotation is a comment on an SpdxItem by an agent."
}
},
"checksums" : {
"description" : "The checksum property provides a mechanism that can be used to verify that the contents of a File or Package have not changed.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"algorithm" : {
"description" : "Identifies the algorithm used to produce the subject Checksum. Currently, SHA-1 is the only supported algorithm. It is anticipated that other algorithms will be supported at a later time.",
"type" : "string",
"enum" : [ "SHA256", "SHA1", "SHA384", "MD2", "MD4", "SHA512", "MD6", "MD5", "SHA224" ]
},
"checksumValue" : {
"description" : "The checksumValue property provides a lower case hexidecimal encoded digest value produced using a specific algorithm.",
"type" : "string"
}
},
"description" : "A Checksum is value that allows the contents of a file to be authenticated. Even small changes to the content of the file will change its checksum. This class allows the results of a variety of checksum and cryptographic message digest algorithms to be represented."
},
"minItems" : 1
},
"noticeText" : {
"description" : "This field provides a place for the SPDX file creator to record potential legal notices found in the file. This may or may not include copyright statements.",
"type" : "string"
},
"artifactOfs" : {
"description" : "Indicates the project in which the SpdxElement originated. Tools must preserve doap:homepage and doap:name properties and the URI (if one is known) of doap:Project resources that are values of this property. All other properties of doap:Projects are not directly supported by SPDX and may be dropped when translating to or from some SPDX formats.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : { }
}
},
"licenseComments" : {
"description" : "The licenseComments property allows the preparer of the SPDX document to describe why the licensing in spdx:licenseConcluded was chosen.",
"type" : "string"
},
"fileName" : {
"description" : "The name of the file relative to the root of the package.",
"type" : "string"
},
"name" : {
"description" : "Identify name of this SpdxElement.",
"type" : "string"
},
"comment" : {
"type" : "string"
},
"copyrightText" : {
"description" : "The text of copyright declarations recited in the Package or File.",
"type" : "string"
},
"fileContributors" : {
"description" : "This field provides a place for the SPDX file creator to record file contributors. Contributors could include names of copyright holders and/or authors who may not be copyright holders yet contributed to the file content.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX file creator to record file contributors. Contributors could include names of copyright holders and/or authors who may not be copyright holders yet contributed to the file content.",
"type" : "string"
}
},
"licenseInfoInFiles" : {
"description" : "Licensing information that was discovered directly in the subject file. This is also considered a declared license for the file.",
"type" : "array",
"items" : {
"description" : "License expression for licenseInfoInFile. Licensing information that was discovered directly in the subject file. This is also considered a declared license for the file.",
"type" : "string"
},
"minItems" : 1
},
"licenseInfoFromFiles" : {
"description" : "The licensing information that was discovered directly within the package. There will be an instance of this property for each distinct value of alllicenseInfoInFile properties of all files contained in the package.",
"type" : "array",
"items" : {
"description" : "License expression for licenseInfoFromFiles. The licensing information that was discovered directly within the package. There will be an instance of this property for each distinct value of alllicenseInfoInFile properties of all files contained in the package.",
"type" : "string"
}
},
"fileDependencies" : {
"type" : "array",
"items" : {
"description" : "SPDX ID for File",
"type" : "string"
}
}
}
}
},
"snippets" : {
"description" : "Snippets referenced in the SPDX document",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"ranges" : {
"description" : "This field defines the byte range in the original host file (in X.2) that the snippet information applies to",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"startPointer" : {
"type" : "object",
"properties" : {
"reference" : {
"description" : "SPDX ID for File",
"type" : "string"
}
}
},
"endPointer" : {
"type" : "object",
"properties" : {
"reference" : {
"description" : "SPDX ID for File",
"type" : "string"
}
}
}
}
},
"minItems" : 1
},
"licenseComments" : {
"description" : "The licenseComments property allows the preparer of the SPDX document to describe why the licensing in spdx:licenseConcluded was chosen.",
"type" : "string"
},
"attributionTexts" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include theactual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include theactual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "string"
}
},
"name" : {
"description" : "Identify name of this SpdxElement.",
"type" : "string"
},
"snippetFromFile" : {
"description" : "SPDX ID for File. File containing the SPDX element (e.g. the file contaning a snippet).",
"type" : "string"
},
"comment" : {
"type" : "string"
},
"copyrightText" : {
"description" : "The text of copyright declarations recited in the Package or File.",
"type" : "string"
},
"licenseInfoInSnippets" : {
"description" : "Licensing information that was discovered directly in the subject snippet. This is also considered a declared license for the snippet.",
"type" : "array",
"items" : {
"description" : "License expression for licenseInfoInSnippet. Licensing information that was discovered directly in the subject snippet. This is also considered a declared license for the snippet.",
"type" : "string"
}
},
"annotations" : {
"description" : "Provide additional information about an SpdxElement.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"annotationDate" : {
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
"type" : "string"
},
"comment" : {
"type" : "string"
},
"annotator" : {
"description" : "This field identifies the person, organization or tool that has commented on a file, package, or the entire document.",
"type" : "string"
},
"annotationType" : {
"description" : "Type of the annotation.",
"type" : "string",
"enum" : [ "OTHER", "REVIEW" ]
}
},
"description" : "An Annotation is a comment on an SpdxItem by an agent."
}
},
"licenseInfoFromFiles" : {
"description" : "The licensing information that was discovered directly within the package. There will be an instance of this property for each distinct value of alllicenseInfoInFile properties of all files contained in the package.",
"type" : "array",
"items" : {
"description" : "License expression for licenseInfoFromFiles. The licensing information that was discovered directly within the package. There will be an instance of this property for each distinct value of alllicenseInfoInFile properties of all files contained in the package.",
"type" : "string"
}
}
}
}
},
"relationships" : {
"description" : "Relationships referenced in the SPDX document",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"comment" : {
"type" : "string"
},
"relationshipType" : {
"description" : "Describes the type of relationship between two SPDX elements.",
"type" : "string",
"enum" : [ "VARIANT_OF", "COPY_OF", "PATCH_FOR", "TEST_DEPENDENCY_OF", "CONTAINED_BY", "DATA_FILE_OF", "OPTIONAL_COMPONENT_OF", "ANCESTOR_OF", "GENERATES", "CONTAINS", "OPTIONAL_DEPENDENCY_OF", "FILE_ADDED", "DEV_DEPENDENCY_OF", "DEPENDENCY_OF", "BUILD_DEPENDENCY_OF", "DESCRIBES", "PREREQUISITE_FOR", "HAS_PREREQUISITE", "PROVIDED_DEPENDENCY_OF", "DYNAMIC_LINK", "DESCRIBED_BY", "METAFILE_OF", "DEPENDENCY_MANIFEST_OF", "PATCH_APPLIED", "RUNTIME_DEPENDENCY_OF", "TEST_OF", "TEST_TOOL_OF", "DEPENDS_ON", "FILE_MODIFIED", "DISTRIBUTION_ARTIFACT", "DOCUMENTATION_OF", "GENERATED_FROM", "STATIC_LINK", "OTHER", "BUILD_TOOL_OF", "TEST_CASE_OF", "PACKAGE_OF", "DESCENDANT_OF", "FILE_DELETED", "EXPANDED_FROM_ARCHIVE", "DEV_TOOL_OF", "EXAMPLE_OF" ]
},
"relatedSpdxElement" : {
"description" : "SPDX ID for SpdxElement. A related SpdxElement.",
"type" : "string"
}
}
}
}
}
}
}
}
+740
View File
@@ -0,0 +1,740 @@
{
"$schema" : "http://json-schema.org/draft-07/schema#",
"$id" : "http://spdx.org/rdf/terms/2.3",
"title" : "SPDX 2.3",
"type" : "object",
"properties" : {
"SPDXID" : {
"type" : "string",
"description" : "Uniquely identify any element in an SPDX document which may be referenced by other elements."
},
"annotations" : {
"description" : "Provide additional information about an SpdxElement.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"annotationDate" : {
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
"type" : "string"
},
"annotationType" : {
"description" : "Type of the annotation.",
"type" : "string",
"enum" : [ "OTHER", "REVIEW" ]
},
"annotator" : {
"description" : "This field identifies the person, organization, or tool that has commented on a file, package, snippet, or the entire document.",
"type" : "string"
},
"comment" : {
"type" : "string"
}
},
"required" : [ "annotationDate", "annotationType", "annotator", "comment" ],
"additionalProperties" : false,
"description" : "An Annotation is a comment on an SpdxItem by an agent."
}
},
"comment" : {
"type" : "string"
},
"creationInfo" : {
"type" : "object",
"properties" : {
"comment" : {
"type" : "string"
},
"created" : {
"description" : "Identify when the SPDX document was originally created. The date is to be specified according to combined date and time in UTC format as specified in ISO 8601 standard.",
"type" : "string"
},
"creators" : {
"description" : "Identify who (or what, in the case of a tool) created the SPDX document. If the SPDX document was created by an individual, indicate the person's name. If the SPDX document was created on behalf of a company or organization, indicate the entity name. If the SPDX document was created using a software tool, indicate the name and version for that tool. If multiple participants or tools were involved, use multiple instances of this field. Person name or organization name may be designated as “anonymous” if appropriate.",
"minItems" : 1,
"type" : "array",
"items" : {
"description" : "Identify who (or what, in the case of a tool) created the SPDX document. If the SPDX document was created by an individual, indicate the person's name. If the SPDX document was created on behalf of a company or organization, indicate the entity name. If the SPDX document was created using a software tool, indicate the name and version for that tool. If multiple participants or tools were involved, use multiple instances of this field. Person name or organization name may be designated as “anonymous” if appropriate.",
"type" : "string"
}
},
"licenseListVersion" : {
"description" : "An optional field for creators of the SPDX file to provide the version of the SPDX License List used when the SPDX file was created.",
"type" : "string"
}
},
"required" : [ "created", "creators" ],
"additionalProperties" : false,
"description" : "One instance is required for each SPDX file produced. It provides the necessary information for forward and backward compatibility for processing tools."
},
"dataLicense" : {
"description" : "License expression for dataLicense. See SPDX Annex D for the license expression syntax. Compliance with the SPDX specification includes populating the SPDX fields therein with data related to such fields (\"SPDX-Metadata\"). The SPDX specification contains numerous fields where an SPDX document creator may provide relevant explanatory text in SPDX-Metadata. Without opining on the lawfulness of \"database rights\" (in jurisdictions where applicable), such explanatory text is copyrightable subject matter in most Berne Convention countries. By using the SPDX specification, or any portion hereof, you hereby agree that any copyright rights (as determined by your jurisdiction) in any SPDX-Metadata, including without limitation explanatory text, shall be subject to the terms of the Creative Commons CC0 1.0 Universal license. For SPDX-Metadata not containing any copyright rights, you hereby agree and acknowledge that the SPDX-Metadata is provided to you \"as-is\" and without any representations or warranties of any kind concerning the SPDX-Metadata, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non-infringement, or the absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.",
"type" : "string"
},
"externalDocumentRefs" : {
"description" : "Identify any external SPDX documents referenced within this SPDX document.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"checksum" : {
"type" : "object",
"properties" : {
"algorithm" : {
"description" : "Identifies the algorithm used to produce the subject Checksum. Currently, SHA-1 is the only supported algorithm. It is anticipated that other algorithms will be supported at a later time.",
"type" : "string",
"enum" : [ "SHA1", "BLAKE3", "SHA3-384", "SHA256", "SHA384", "BLAKE2b-512", "BLAKE2b-256", "SHA3-512", "MD2", "ADLER32", "MD4", "SHA3-256", "BLAKE2b-384", "SHA512", "MD6", "MD5", "SHA224" ]
},
"checksumValue" : {
"description" : "The checksumValue property provides a lower case hexidecimal encoded digest value produced using a specific algorithm.",
"type" : "string"
}
},
"required" : [ "algorithm", "checksumValue" ],
"additionalProperties" : false,
"description" : "A Checksum is value that allows the contents of a file to be authenticated. Even small changes to the content of the file will change its checksum. This class allows the results of a variety of checksum and cryptographic message digest algorithms to be represented."
},
"externalDocumentId" : {
"description" : "externalDocumentId is a string containing letters, numbers, ., - and/or + which uniquely identifies an external document within this document.",
"type" : "string"
},
"spdxDocument" : {
"description" : "SPDX ID for SpdxDocument. A property containing an SPDX document.",
"type" : "string"
}
},
"required" : [ "checksum", "externalDocumentId", "spdxDocument" ],
"additionalProperties" : false,
"description" : "Information about an external SPDX document reference including the checksum. This allows for verification of the external references."
}
},
"hasExtractedLicensingInfos" : {
"description" : "Indicates that a particular ExtractedLicensingInfo was defined in the subject SpdxDocument.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"comment" : {
"type" : "string"
},
"crossRefs" : {
"description" : "Cross Reference Detail for a license SeeAlso URL",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"isLive" : {
"description" : "Indicate a URL is still a live accessible location on the public internet",
"type" : "boolean"
},
"isValid" : {
"description" : "True if the URL is a valid well formed URL",
"type" : "boolean"
},
"isWayBackLink" : {
"description" : "True if the License SeeAlso URL points to a Wayback archive",
"type" : "boolean"
},
"match" : {
"description" : "Status of a License List SeeAlso URL reference if it refers to a website that matches the license text.",
"type" : "string"
},
"order" : {
"description" : "The ordinal order of this element within a list",
"type" : "integer"
},
"timestamp" : {
"description" : "Timestamp",
"type" : "string"
},
"url" : {
"description" : "URL Reference",
"type" : "string"
}
},
"required" : [ "url" ],
"additionalProperties" : false,
"description" : "Cross reference details for the a URL reference"
}
},
"extractedText" : {
"description" : "Provide a copy of the actual text of the license reference extracted from the package, file or snippet that is associated with the License Identifier to aid in future analysis.",
"type" : "string"
},
"licenseId" : {
"description" : "A human readable short form license identifier for a license. The license ID is either on the standard license list or the form \"LicenseRef-[idString]\" where [idString] is a unique string containing letters, numbers, \".\" or \"-\". When used within a license expression, the license ID can optionally include a reference to an external document in the form \"DocumentRef-[docrefIdString]:LicenseRef-[idString]\" where docRefIdString is an ID for an external document reference.",
"type" : "string"
},
"name" : {
"description" : "Identify name of this SpdxElement.",
"type" : "string"
},
"seeAlsos" : {
"type" : "array",
"items" : {
"type" : "string"
}
}
},
"required" : [ "extractedText", "licenseId" ],
"additionalProperties" : false,
"description" : "An ExtractedLicensingInfo represents a license or licensing notice that was found in a package, file or snippet. Any license text that is recognized as a license may be represented as a License rather than an ExtractedLicensingInfo."
}
},
"name" : {
"description" : "Identify name of this SpdxElement.",
"type" : "string"
},
"revieweds" : {
"description" : "Reviewed",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"comment" : {
"type" : "string"
},
"reviewDate" : {
"description" : "The date and time at which the SpdxDocument was reviewed. This value must be in UTC and have 'Z' as its timezone indicator.",
"type" : "string"
},
"reviewer" : {
"description" : "The name and, optionally, contact information of the person who performed the review. Values of this property must conform to the agent and tool syntax. The reviewer property is deprecated in favor of Annotation with an annotationType review.",
"type" : "string"
}
},
"required" : [ "reviewDate" ],
"additionalProperties" : false,
"description" : "This class has been deprecated in favor of an Annotation with an Annotation type of review."
}
},
"spdxVersion" : {
"description" : "Provide a reference number that can be used to understand how to parse and interpret the rest of the file. It will enable both future changes to the specification and to support backward compatibility. The version number consists of a major and minor version indicator. The major field will be incremented when incompatible changes between versions are made (one or more sections are created, modified or deleted). The minor field will be incremented when backwards compatible changes are made.",
"type" : "string"
},
"documentNamespace" : {
"type" : "string",
"description" : "The URI provides an unambiguous mechanism for other SPDX documents to reference SPDX elements within this SPDX document."
},
"documentDescribes" : {
"description" : "Packages, files and/or Snippets described by this SPDX document",
"type" : "array",
"items" : {
"type" : "string",
"description" : "SPDX ID for each Package, File, or Snippet."
}
},
"packages" : {
"description" : "Packages referenced in the SPDX document",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"SPDXID" : {
"type" : "string",
"description" : "Uniquely identify any element in an SPDX document which may be referenced by other elements."
},
"annotations" : {
"description" : "Provide additional information about an SpdxElement.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"annotationDate" : {
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
"type" : "string"
},
"annotationType" : {
"description" : "Type of the annotation.",
"type" : "string",
"enum" : [ "OTHER", "REVIEW" ]
},
"annotator" : {
"description" : "This field identifies the person, organization, or tool that has commented on a file, package, snippet, or the entire document.",
"type" : "string"
},
"comment" : {
"type" : "string"
}
},
"required" : [ "annotationDate", "annotationType", "annotator", "comment" ],
"additionalProperties" : false,
"description" : "An Annotation is a comment on an SpdxItem by an agent."
}
},
"attributionTexts" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "string"
}
},
"builtDate" : {
"description" : "This field provides a place for recording the actual date the package was built.",
"type" : "string"
},
"checksums" : {
"description" : "The checksum property provides a mechanism that can be used to verify that the contents of a File or Package have not changed.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"algorithm" : {
"description" : "Identifies the algorithm used to produce the subject Checksum. Currently, SHA-1 is the only supported algorithm. It is anticipated that other algorithms will be supported at a later time.",
"type" : "string",
"enum" : [ "SHA1", "BLAKE3", "SHA3-384", "SHA256", "SHA384", "BLAKE2b-512", "BLAKE2b-256", "SHA3-512", "MD2", "ADLER32", "MD4", "SHA3-256", "BLAKE2b-384", "SHA512", "MD6", "MD5", "SHA224" ]
},
"checksumValue" : {
"description" : "The checksumValue property provides a lower case hexidecimal encoded digest value produced using a specific algorithm.",
"type" : "string"
}
},
"required" : [ "algorithm", "checksumValue" ],
"additionalProperties" : false,
"description" : "A Checksum is value that allows the contents of a file to be authenticated. Even small changes to the content of the file will change its checksum. This class allows the results of a variety of checksum and cryptographic message digest algorithms to be represented."
}
},
"comment" : {
"type" : "string"
},
"copyrightText" : {
"description" : "The text of copyright declarations recited in the package, file or snippet.\n\nIf the copyrightText field is not present, it implies an equivalent meaning to NOASSERTION.",
"type" : "string"
},
"description" : {
"description" : "Provides a detailed description of the package.",
"type" : "string"
},
"downloadLocation" : {
"description" : "The URI at which this package is available for download. Private (i.e., not publicly reachable) URIs are acceptable as values of this property. The values http://spdx.org/rdf/terms#none and http://spdx.org/rdf/terms#noassertion may be used to specify that the package is not downloadable or that no attempt was made to determine its download location, respectively.",
"type" : "string"
},
"externalRefs" : {
"description" : "An External Reference allows a Package to reference an external source of additional information, metadata, enumerations, asset identifiers, or downloadable content believed to be relevant to the Package.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"comment" : {
"type" : "string"
},
"referenceCategory" : {
"description" : "Category for the external reference",
"type" : "string",
"enum" : [ "OTHER", "PERSISTENT-ID", "PERSISTENT_ID", "SECURITY", "PACKAGE-MANAGER", "PACKAGE_MANAGER" ]
},
"referenceLocator" : {
"description" : "The unique string with no spaces necessary to access the package-specific information, metadata, or content within the target location. The format of the locator is subject to constraints defined by the <type>.",
"type" : "string"
},
"referenceType" : {
"description" : "Type of the external reference. These are defined in an appendix in the SPDX specification.",
"type" : "string"
}
},
"required" : [ "referenceCategory", "referenceLocator", "referenceType" ],
"additionalProperties" : false,
"description" : "An External Reference allows a Package to reference an external source of additional information, metadata, enumerations, asset identifiers, or downloadable content believed to be relevant to the Package."
}
},
"filesAnalyzed" : {
"description" : "Indicates whether the file content of this package has been available for or subjected to analysis when creating the SPDX document. If false indicates packages that represent metadata or URI references to a project, product, artifact, distribution or a component. If set to false, the package must not contain any files.",
"type" : "boolean"
},
"hasFiles" : {
"description" : "Indicates that a particular file belongs to a package.",
"type" : "array",
"items" : {
"description" : "SPDX ID for File. Indicates that a particular file belongs to a package.",
"type" : "string"
}
},
"homepage" : {
"type" : "string"
},
"licenseComments" : {
"description" : "The licenseComments property allows the preparer of the SPDX document to describe why the licensing in spdx:licenseConcluded was chosen.",
"type" : "string"
},
"licenseConcluded" : {
"description" : "License expression for licenseConcluded. See SPDX Annex D for the license expression syntax. The licensing that the preparer of this SPDX document has concluded, based on the evidence, actually applies to the SPDX Item.\n\nIf the licenseConcluded field is not present for an SPDX Item, it implies an equivalent meaning to NOASSERTION.",
"type" : "string"
},
"licenseDeclared" : {
"description" : "License expression for licenseDeclared. See SPDX Annex D for the license expression syntax. The licensing that the creators of the software in the package, or the packager, have declared. Declarations by the original software creator should be preferred, if they exist.",
"type" : "string"
},
"licenseInfoFromFiles" : {
"description" : "The licensing information that was discovered directly within the package. There will be an instance of this property for each distinct value of alllicenseInfoInFile properties of all files contained in the package.\n\nIf the licenseInfoFromFiles field is not present for a package and filesAnalyzed property for that same package is true or omitted, it implies an equivalent meaning to NOASSERTION.",
"type" : "array",
"items" : {
"description" : "License expression for licenseInfoFromFiles. See SPDX Annex D for the license expression syntax. The licensing information that was discovered directly within the package. There will be an instance of this property for each distinct value of alllicenseInfoInFile properties of all files contained in the package.\n\nIf the licenseInfoFromFiles field is not present for a package and filesAnalyzed property for that same package is true or omitted, it implies an equivalent meaning to NOASSERTION.",
"type" : "string"
}
},
"name" : {
"description" : "Identify name of this SpdxElement.",
"type" : "string"
},
"originator" : {
"description" : "The name and, optionally, contact information of the person or organization that originally created the package. Values of this property must conform to the agent and tool syntax.",
"type" : "string"
},
"packageFileName" : {
"description" : "The base name of the package file name. For example, zlib-1.2.5.tar.gz.",
"type" : "string"
},
"packageVerificationCode" : {
"type" : "object",
"properties" : {
"packageVerificationCodeExcludedFiles" : {
"description" : "A file that was excluded when calculating the package verification code. This is usually a file containing SPDX data regarding the package. If a package contains more than one SPDX file all SPDX files must be excluded from the package verification code. If this is not done it would be impossible to correctly calculate the verification codes in both files.",
"type" : "array",
"items" : {
"description" : "A file that was excluded when calculating the package verification code. This is usually a file containing SPDX data regarding the package. If a package contains more than one SPDX file all SPDX files must be excluded from the package verification code. If this is not done it would be impossible to correctly calculate the verification codes in both files.",
"type" : "string"
}
},
"packageVerificationCodeValue" : {
"description" : "The actual package verification code as a hex encoded value.",
"type" : "string"
}
},
"required" : [ "packageVerificationCodeValue" ],
"additionalProperties" : false,
"description" : "A manifest based verification code (the algorithm is defined in section 4.7 of the full specification) of the SPDX Item. This allows consumers of this data and/or database to determine if an SPDX item they have in hand is identical to the SPDX item from which the data was produced. This algorithm works even if the SPDX document is included in the SPDX item."
},
"primaryPackagePurpose" : {
"description" : "This field provides information about the primary purpose of the identified package. Package Purpose is intrinsic to how the package is being used rather than the content of the package.",
"type" : "string",
"enum" : [ "OTHER", "INSTALL", "ARCHIVE", "FIRMWARE", "APPLICATION", "FRAMEWORK", "LIBRARY", "CONTAINER", "SOURCE", "DEVICE", "OPERATING_SYSTEM", "FILE" ]
},
"releaseDate" : {
"description" : "This field provides a place for recording the date the package was released.",
"type" : "string"
},
"sourceInfo" : {
"description" : "Allows the producer(s) of the SPDX document to describe how the package was acquired and/or changed from the original source.",
"type" : "string"
},
"summary" : {
"description" : "Provides a short description of the package.",
"type" : "string"
},
"supplier" : {
"description" : "The name and, optionally, contact information of the person or organization who was the immediate supplier of this package to the recipient. The supplier may be different than originator when the software has been repackaged. Values of this property must conform to the agent and tool syntax.",
"type" : "string"
},
"validUntilDate" : {
"description" : "This field provides a place for recording the end of the support period for a package from the supplier.",
"type" : "string"
},
"versionInfo" : {
"description" : "Provides an indication of the version of the package that is described by this SpdxDocument.",
"type" : "string"
}
},
"required" : [ "SPDXID", "downloadLocation", "name" ],
"additionalProperties" : false
}
},
"files" : {
"description" : "Files referenced in the SPDX document",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"SPDXID" : {
"type" : "string",
"description" : "Uniquely identify any element in an SPDX document which may be referenced by other elements."
},
"annotations" : {
"description" : "Provide additional information about an SpdxElement.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"annotationDate" : {
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
"type" : "string"
},
"annotationType" : {
"description" : "Type of the annotation.",
"type" : "string",
"enum" : [ "OTHER", "REVIEW" ]
},
"annotator" : {
"description" : "This field identifies the person, organization, or tool that has commented on a file, package, snippet, or the entire document.",
"type" : "string"
},
"comment" : {
"type" : "string"
}
},
"required" : [ "annotationDate", "annotationType", "annotator", "comment" ],
"additionalProperties" : false,
"description" : "An Annotation is a comment on an SpdxItem by an agent."
}
},
"artifactOfs" : {
"description" : "Indicates the project in which the SpdxElement originated. Tools must preserve doap:homepage and doap:name properties and the URI (if one is known) of doap:Project resources that are values of this property. All other properties of doap:Projects are not directly supported by SPDX and may be dropped when translating to or from some SPDX formats.",
"type" : "array",
"items" : {
"type" : "object"
}
},
"attributionTexts" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "string"
}
},
"checksums" : {
"description" : "The checksum property provides a mechanism that can be used to verify that the contents of a File or Package have not changed.",
"minItems" : 1,
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"algorithm" : {
"description" : "Identifies the algorithm used to produce the subject Checksum. Currently, SHA-1 is the only supported algorithm. It is anticipated that other algorithms will be supported at a later time.",
"type" : "string",
"enum" : [ "SHA1", "BLAKE3", "SHA3-384", "SHA256", "SHA384", "BLAKE2b-512", "BLAKE2b-256", "SHA3-512", "MD2", "ADLER32", "MD4", "SHA3-256", "BLAKE2b-384", "SHA512", "MD6", "MD5", "SHA224" ]
},
"checksumValue" : {
"description" : "The checksumValue property provides a lower case hexidecimal encoded digest value produced using a specific algorithm.",
"type" : "string"
}
},
"required" : [ "algorithm", "checksumValue" ],
"additionalProperties" : false,
"description" : "A Checksum is value that allows the contents of a file to be authenticated. Even small changes to the content of the file will change its checksum. This class allows the results of a variety of checksum and cryptographic message digest algorithms to be represented."
}
},
"comment" : {
"type" : "string"
},
"copyrightText" : {
"description" : "The text of copyright declarations recited in the package, file or snippet.\n\nIf the copyrightText field is not present, it implies an equivalent meaning to NOASSERTION.",
"type" : "string"
},
"fileContributors" : {
"description" : "This field provides a place for the SPDX file creator to record file contributors. Contributors could include names of copyright holders and/or authors who may not be copyright holders yet contributed to the file content.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX file creator to record file contributors. Contributors could include names of copyright holders and/or authors who may not be copyright holders yet contributed to the file content.",
"type" : "string"
}
},
"fileDependencies" : {
"description" : "This field is deprecated since SPDX 2.0 in favor of using Section 7 which provides more granularity about relationships.",
"type" : "array",
"items" : {
"description" : "SPDX ID for File. This field is deprecated since SPDX 2.0 in favor of using Section 7 which provides more granularity about relationships.",
"type" : "string"
}
},
"fileName" : {
"description" : "The name of the file relative to the root of the package.",
"type" : "string"
},
"fileTypes" : {
"description" : "The type of the file.",
"type" : "array",
"items" : {
"description" : "The type of the file.",
"type" : "string",
"enum" : [ "OTHER", "DOCUMENTATION", "IMAGE", "VIDEO", "ARCHIVE", "SPDX", "APPLICATION", "SOURCE", "BINARY", "TEXT", "AUDIO" ]
}
},
"licenseComments" : {
"description" : "The licenseComments property allows the preparer of the SPDX document to describe why the licensing in spdx:licenseConcluded was chosen.",
"type" : "string"
},
"licenseConcluded" : {
"description" : "License expression for licenseConcluded. See SPDX Annex D for the license expression syntax. The licensing that the preparer of this SPDX document has concluded, based on the evidence, actually applies to the SPDX Item.\n\nIf the licenseConcluded field is not present for an SPDX Item, it implies an equivalent meaning to NOASSERTION.",
"type" : "string"
},
"licenseInfoInFiles" : {
"description" : "Licensing information that was discovered directly in the subject file. This is also considered a declared license for the file.\n\nIf the licenseInfoInFile field is not present for a file, it implies an equivalent meaning to NOASSERTION.",
"type" : "array",
"items" : {
"description" : "License expression for licenseInfoInFile. See SPDX Annex D for the license expression syntax. Licensing information that was discovered directly in the subject file. This is also considered a declared license for the file.\n\nIf the licenseInfoInFile field is not present for a file, it implies an equivalent meaning to NOASSERTION.",
"type" : "string"
}
},
"noticeText" : {
"description" : "This field provides a place for the SPDX file creator to record potential legal notices found in the file. This may or may not include copyright statements.",
"type" : "string"
}
},
"required" : [ "SPDXID", "checksums", "fileName" ],
"additionalProperties" : false
}
},
"snippets" : {
"description" : "Snippets referenced in the SPDX document",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"SPDXID" : {
"type" : "string",
"description" : "Uniquely identify any element in an SPDX document which may be referenced by other elements."
},
"annotations" : {
"description" : "Provide additional information about an SpdxElement.",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"annotationDate" : {
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
"type" : "string"
},
"annotationType" : {
"description" : "Type of the annotation.",
"type" : "string",
"enum" : [ "OTHER", "REVIEW" ]
},
"annotator" : {
"description" : "This field identifies the person, organization, or tool that has commented on a file, package, snippet, or the entire document.",
"type" : "string"
},
"comment" : {
"type" : "string"
}
},
"required" : [ "annotationDate", "annotationType", "annotator", "comment" ],
"additionalProperties" : false,
"description" : "An Annotation is a comment on an SpdxItem by an agent."
}
},
"attributionTexts" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "array",
"items" : {
"description" : "This field provides a place for the SPDX data creator to record acknowledgements that may be required to be communicated in some contexts. This is not meant to include the actual complete license text (see licenseConculded and licenseDeclared), and may or may not include copyright notices (see also copyrightText). The SPDX data creator may use this field to record other acknowledgements, such as particular clauses from license texts, which may be necessary or desirable to reproduce.",
"type" : "string"
}
},
"comment" : {
"type" : "string"
},
"copyrightText" : {
"description" : "The text of copyright declarations recited in the package, file or snippet.\n\nIf the copyrightText field is not present, it implies an equivalent meaning to NOASSERTION.",
"type" : "string"
},
"licenseComments" : {
"description" : "The licenseComments property allows the preparer of the SPDX document to describe why the licensing in spdx:licenseConcluded was chosen.",
"type" : "string"
},
"licenseConcluded" : {
"description" : "License expression for licenseConcluded. See SPDX Annex D for the license expression syntax. The licensing that the preparer of this SPDX document has concluded, based on the evidence, actually applies to the SPDX Item.\n\nIf the licenseConcluded field is not present for an SPDX Item, it implies an equivalent meaning to NOASSERTION.",
"type" : "string"
},
"licenseInfoInSnippets" : {
"description" : "Licensing information that was discovered directly in the subject snippet. This is also considered a declared license for the snippet.\n\nIf the licenseInfoInSnippet field is not present for a snippet, it implies an equivalent meaning to NOASSERTION.",
"type" : "array",
"items" : {
"description" : "License expression for licenseInfoInSnippet. See SPDX Annex D for the license expression syntax. Licensing information that was discovered directly in the subject snippet. This is also considered a declared license for the snippet.\n\nIf the licenseInfoInSnippet field is not present for a snippet, it implies an equivalent meaning to NOASSERTION.",
"type" : "string"
}
},
"name" : {
"description" : "Identify name of this SpdxElement.",
"type" : "string"
},
"ranges" : {
"description" : "This field defines the byte range in the original host file (in X.2) that the snippet information applies to",
"minItems" : 1,
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"endPointer" : {
"type" : "object",
"properties" : {
"reference" : {
"description" : "SPDX ID for File",
"type" : "string"
},
"offset" : {
"type" : "integer",
"description" : "Byte offset in the file"
},
"lineNumber" : {
"type" : "integer",
"description" : "line number offset in the file"
}
},
"required" : [ "reference" ],
"additionalProperties" : false
},
"startPointer" : {
"type" : "object",
"properties" : {
"reference" : {
"description" : "SPDX ID for File",
"type" : "string"
},
"offset" : {
"type" : "integer",
"description" : "Byte offset in the file"
},
"lineNumber" : {
"type" : "integer",
"description" : "line number offset in the file"
}
},
"required" : [ "reference" ],
"additionalProperties" : false
}
},
"required" : [ "endPointer", "startPointer" ],
"additionalProperties" : false
}
},
"snippetFromFile" : {
"description" : "SPDX ID for File. File containing the SPDX element (e.g. the file contaning a snippet).",
"type" : "string"
}
},
"required" : [ "SPDXID", "name", "ranges", "snippetFromFile" ],
"additionalProperties" : false
}
},
"relationships" : {
"description" : "Relationships referenced in the SPDX document",
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"spdxElementId" : {
"type" : "string",
"description" : "Id to which the SPDX element is related"
},
"comment" : {
"type" : "string"
},
"relatedSpdxElement" : {
"description" : "SPDX ID for SpdxElement. A related SpdxElement.",
"type" : "string"
},
"relationshipType" : {
"description" : "Describes the type of relationship between two SPDX elements.",
"type" : "string",
"enum" : [ "VARIANT_OF", "COPY_OF", "PATCH_FOR", "TEST_DEPENDENCY_OF", "CONTAINED_BY", "DATA_FILE_OF", "OPTIONAL_COMPONENT_OF", "ANCESTOR_OF", "GENERATES", "CONTAINS", "OPTIONAL_DEPENDENCY_OF", "FILE_ADDED", "REQUIREMENT_DESCRIPTION_FOR", "DEV_DEPENDENCY_OF", "DEPENDENCY_OF", "BUILD_DEPENDENCY_OF", "DESCRIBES", "PREREQUISITE_FOR", "HAS_PREREQUISITE", "PROVIDED_DEPENDENCY_OF", "DYNAMIC_LINK", "DESCRIBED_BY", "METAFILE_OF", "DEPENDENCY_MANIFEST_OF", "PATCH_APPLIED", "RUNTIME_DEPENDENCY_OF", "TEST_OF", "TEST_TOOL_OF", "DEPENDS_ON", "SPECIFICATION_FOR", "FILE_MODIFIED", "DISTRIBUTION_ARTIFACT", "AMENDS", "DOCUMENTATION_OF", "GENERATED_FROM", "STATIC_LINK", "OTHER", "BUILD_TOOL_OF", "TEST_CASE_OF", "PACKAGE_OF", "DESCENDANT_OF", "FILE_DELETED", "EXPANDED_FROM_ARCHIVE", "DEV_TOOL_OF", "EXAMPLE_OF" ]
}
},
"required" : [ "spdxElementId", "relatedSpdxElement", "relationshipType" ],
"additionalProperties" : false
}
}
},
"required" : [ "SPDXID", "creationInfo", "dataLicense", "name", "spdxVersion", "documentNamespace" ],
"additionalProperties" : false
}
+1 -1
View File
@@ -19,7 +19,7 @@ func IDByHash(obj interface{}) (ID, error) {
SlicesAsSets: true,
})
if err != nil {
return "", fmt.Errorf("could not build ID for object=%+v: %+v", obj, err)
return "", fmt.Errorf("could not build ID for object=%+v: %w", obj, err)
}
return ID(fmt.Sprintf("%x", f)), nil
+12 -9
View File
@@ -10,19 +10,22 @@ const (
// ContainsRelationship (supports any-to-any linkages) is a proxy for the SPDX 2.2 CONTAINS relationship.
ContainsRelationship RelationshipType = "contains"
// RuntimeDependencyOfRelationship is a proxy for the SPDX 2.2.1 RUNTIME_DEPENDENCY_OF relationship.
RuntimeDependencyOfRelationship RelationshipType = "runtime-dependency-of"
// DevDependencyOfRelationship is a proxy for the SPDX 2.2.1 DEV_DEPENDENCY_OF relationship.
DevDependencyOfRelationship RelationshipType = "dev-dependency-of"
// BuildDependencyOfRelationship is a proxy for the SPDX 2.2.1 BUILD_DEPENDENCY_OF relationship.
BuildDependencyOfRelationship RelationshipType = "build-dependency-of"
// DependencyOfRelationship is a proxy for the SPDX 2.2.1 DEPENDENCY_OF relationship.
DependencyOfRelationship RelationshipType = "dependency-of"
// DescribedByRelationship is a proxy for the SPDX 2.2.2 DESCRIBED_BY relationship.
DescribedByRelationship RelationshipType = "described-by"
)
func AllRelationshipTypes() []RelationshipType {
return []RelationshipType{
OwnershipByFileOverlapRelationship,
ContainsRelationship,
DependencyOfRelationship,
DescribedByRelationship,
}
}
type RelationshipType string
type Relationship struct {
@@ -1,4 +1,4 @@
package pkg
package cpe
import (
"sort"
@@ -6,15 +6,15 @@ import (
"github.com/facebookincubator/nvdtools/wfn"
)
var _ sort.Interface = (*CPEBySpecificity)(nil)
var _ sort.Interface = (*BySpecificity)(nil)
type CPEBySpecificity []wfn.Attributes
type BySpecificity []wfn.Attributes
func (c CPEBySpecificity) Len() int { return len(c) }
func (c BySpecificity) Len() int { return len(c) }
func (c CPEBySpecificity) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c BySpecificity) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c CPEBySpecificity) Less(i, j int) bool {
func (c BySpecificity) Less(i, j int) bool {
iScore := weightedCountForSpecifiedFields(c[i])
jScore := weightedCountForSpecifiedFields(c[j])
@@ -29,7 +29,7 @@ func (c CPEBySpecificity) Less(i, j int) bool {
}
// if score and length are equal then text sort
// note that we are not using CPEString from the syft pkg
// note that we are not using String from the syft pkg
// as we are not encoding/decoding this CPE string so we don't
// need the proper quoted version of the CPE.
return c[i].BindToFmtString() < c[j].BindToFmtString()
+98
View File
@@ -0,0 +1,98 @@
package cpe
import (
"sort"
"testing"
"github.com/stretchr/testify/assert"
)
func Test_BySpecificity(t *testing.T) {
tests := []struct {
name string
input []CPE
expected []CPE
}{
{
name: "sort strictly by wfn *",
input: []CPE{
Must("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:*:package:1:*:*:*:*:some:*:*"),
Must("cpe:2.3:a:some:package:1:*:*:*:*:some:*:*"),
Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
},
expected: []CPE{
Must("cpe:2.3:a:some:package:1:*:*:*:*:some:*:*"),
Must("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:*:package:1:*:*:*:*:some:*:*"),
Must("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
},
},
{
name: "sort strictly by field length",
input: []CPE{
Must("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:1:333:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:666666:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:1:1:*:*:*:*:4444:*:*"),
},
expected: []CPE{
Must("cpe:2.3:a:1:666666:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:1:1:*:*:*:*:4444:*:*"),
Must("cpe:2.3:a:1:1:333:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
},
},
{
name: "sort by mix of field length and specificity",
input: []CPE{
Must("cpe:2.3:a:1:666666:*:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:*:1:1:*:*:*:*:4444:*:*"),
Must("cpe:2.3:a:1:*:333:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
},
expected: []CPE{
Must("cpe:2.3:a:55555:1:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:22:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:1:1:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:1:666666:*:*:*:*:*:1:*:*"),
Must("cpe:2.3:a:*:1:1:*:*:*:*:4444:*:*"),
Must("cpe:2.3:a:1:*:333:*:*:*:*:*:*:*"),
},
},
{
name: "sort by mix of field length, specificity, dash",
input: []CPE{
Must("cpe:2.3:a:alpine:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine_keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine-keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine-keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine_keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
},
expected: []CPE{
Must("cpe:2.3:a:alpine-keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine-keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine_keys:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine_keys:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine:alpine-keys:2.3-r1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:alpine:alpine_keys:2.3-r1:*:*:*:*:*:*:*"),
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
sort.Sort(BySpecificity(test.input))
assert.Equal(t, test.expected, test.input)
})
}
}
+30 -30
View File
@@ -1,4 +1,4 @@
package pkg
package cpe
import (
"fmt"
@@ -24,17 +24,17 @@ const cpeRegexString = ((`^([c][pP][eE]:/[AHOaho]?(:[A-Za-z0-9\._\-~%]*){0,6})`)
var cpeRegex = regexp.MustCompile(cpeRegexString)
// NewCPE will parse a formatted CPE string and return a CPE object. Some input, such as the existence of whitespace
// New will parse a formatted CPE string and return a CPE object. Some input, such as the existence of whitespace
// characters is allowed, however, a more strict validation is done after this sanitization process.
func NewCPE(cpeStr string) (CPE, error) {
func New(cpeStr string) (CPE, error) {
// get a CPE object based on the given string --don't validate yet since it may be possible to escape select cases on the callers behalf
c, err := newCPEWithoutValidation(cpeStr)
c, err := newWithoutValidation(cpeStr)
if err != nil {
return CPE{}, fmt.Errorf("unable to parse CPE string: %w", err)
}
// ensure that this CPE can be validated after being fully sanitized
if ValidateCPEString(CPEString(c)) != nil {
if ValidateString(String(c)) != nil {
return CPE{}, err
}
@@ -43,7 +43,16 @@ func NewCPE(cpeStr string) (CPE, error) {
return c, nil
}
func ValidateCPEString(cpeStr string) error {
// Must returns a CPE or panics if the provided string is not valid
func Must(cpeStr string) CPE {
c, err := New(cpeStr)
if err != nil {
panic(err)
}
return c
}
func ValidateString(cpeStr string) error {
// We should filter out all CPEs that do not match the official CPE regex
// The facebook nvdtools parser can sometimes incorrectly parse invalid CPE strings
if !cpeRegex.MatchString(cpeStr) {
@@ -52,7 +61,7 @@ func ValidateCPEString(cpeStr string) error {
return nil
}
func newCPEWithoutValidation(cpeStr string) (CPE, error) {
func newWithoutValidation(cpeStr string) (CPE, error) {
value, err := wfn.Parse(cpeStr)
if err != nil {
return CPE{}, fmt.Errorf("failed to parse CPE=%q: %w", cpeStr, err)
@@ -63,30 +72,22 @@ func newCPEWithoutValidation(cpeStr string) (CPE, error) {
}
// we need to compare the raw data since we are constructing CPEs in other locations
value.Vendor = normalizeCpeField(value.Vendor)
value.Product = normalizeCpeField(value.Product)
value.Language = normalizeCpeField(value.Language)
value.Version = normalizeCpeField(value.Version)
value.TargetSW = normalizeCpeField(value.TargetSW)
value.Part = normalizeCpeField(value.Part)
value.Edition = normalizeCpeField(value.Edition)
value.Other = normalizeCpeField(value.Other)
value.SWEdition = normalizeCpeField(value.SWEdition)
value.TargetHW = normalizeCpeField(value.TargetHW)
value.Update = normalizeCpeField(value.Update)
value.Vendor = normalizeField(value.Vendor)
value.Product = normalizeField(value.Product)
value.Language = normalizeField(value.Language)
value.Version = normalizeField(value.Version)
value.TargetSW = normalizeField(value.TargetSW)
value.Part = normalizeField(value.Part)
value.Edition = normalizeField(value.Edition)
value.Other = normalizeField(value.Other)
value.SWEdition = normalizeField(value.SWEdition)
value.TargetHW = normalizeField(value.TargetHW)
value.Update = normalizeField(value.Update)
return *value, nil
}
func MustCPE(cpeStr string) CPE {
c, err := NewCPE(cpeStr)
if err != nil {
panic(err)
}
return c
}
func normalizeCpeField(field string) string {
func normalizeField(field string) string {
// replace spaces with underscores (per section 5.3.2 of the CPE spec v 2.3)
field = strings.ReplaceAll(field, " ", "_")
@@ -105,14 +106,13 @@ func stripSlashes(s string) string {
for i, c := range s {
if c == '\\' && i+1 < len(s) && strings.ContainsRune(allowedCPEPunctuation, rune(s[i+1])) {
continue
} else {
sb.WriteRune(c)
}
sb.WriteRune(c)
}
return sb.String()
}
func CPEString(c CPE) string {
func String(c CPE) string {
output := CPE{}
output.Vendor = sanitize(c.Vendor)
output.Product = sanitize(c.Product)
+19 -26
View File
@@ -1,4 +1,4 @@
package pkg
package cpe
import (
"encoding/json"
@@ -11,14 +11,7 @@ import (
"github.com/stretchr/testify/require"
)
func must(c CPE, e error) CPE {
if e != nil {
panic(e)
}
return c
}
func TestNewCPE(t *testing.T) {
func Test_New(t *testing.T) {
tests := []struct {
name string
input string
@@ -27,29 +20,29 @@ func TestNewCPE(t *testing.T) {
{
name: "gocase",
input: `cpe:/a:10web:form_maker:1.0.0::~~~wordpress~~`,
expected: must(NewCPE(`cpe:2.3:a:10web:form_maker:1.0.0:*:*:*:*:wordpress:*:*`)),
expected: Must(`cpe:2.3:a:10web:form_maker:1.0.0:*:*:*:*:wordpress:*:*`),
},
{
name: "dashes",
input: `cpe:/a:7-zip:7-zip:4.56:beta:~~~windows~~`,
expected: must(NewCPE(`cpe:2.3:a:7-zip:7-zip:4.56:beta:*:*:*:windows:*:*`)),
expected: Must(`cpe:2.3:a:7-zip:7-zip:4.56:beta:*:*:*:windows:*:*`),
},
{
name: "URL escape characters",
input: `cpe:/a:%240.99_kindle_books_project:%240.99_kindle_books:6::~~~android~~`,
expected: must(NewCPE(`cpe:2.3:a:\$0.99_kindle_books_project:\$0.99_kindle_books:6:*:*:*:*:android:*:*`)),
expected: Must(`cpe:2.3:a:\$0.99_kindle_books_project:\$0.99_kindle_books:6:*:*:*:*:android:*:*`),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual, err := NewCPE(test.input)
actual, err := New(test.input)
if err != nil {
t.Fatalf("got an error while creating CPE: %+v", err)
}
if CPEString(actual) != CPEString(test.expected) {
t.Errorf("mismatched entries:\n\texpected:%+v\n\t actual:%+v\n", CPEString(test.expected), CPEString(actual))
if String(actual) != String(test.expected) {
t.Errorf("mismatched entries:\n\texpected:%+v\n\t actual:%+v\n", String(test.expected), String(actual))
}
})
@@ -81,7 +74,7 @@ func Test_normalizeCpeField(t *testing.T) {
}
for _, test := range tests {
t.Run(test.field, func(t *testing.T) {
assert.Equal(t, test.expected, normalizeCpeField(test.field))
assert.Equal(t, test.expected, normalizeField(test.field))
})
}
}
@@ -98,14 +91,14 @@ func Test_CPEParser(t *testing.T) {
for _, test := range testCases {
t.Run(test.CPEString, func(t *testing.T) {
c1, err := NewCPE(test.CPEString)
c1, err := New(test.CPEString)
assert.NoError(t, err)
c2, err := NewCPE(test.CPEUrl)
c2, err := New(test.CPEUrl)
assert.NoError(t, err)
assert.Equal(t, c1, c2)
assert.Equal(t, c1, test.WFN)
assert.Equal(t, c2, test.WFN)
assert.Equal(t, CPEString(test.WFN), test.CPEString)
assert.Equal(t, String(test.WFN), test.CPEString)
})
}
}
@@ -167,16 +160,16 @@ func Test_InvalidCPE(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
c, err := NewCPE(test.in)
c, err := New(test.in)
if test.expectedErr {
assert.Error(t, err)
if t.Failed() {
t.Logf("got CPE: %q details: %+v", CPEString(c), c)
t.Logf("got CPE: %q details: %+v", String(c), c)
}
return
}
require.NoError(t, err)
assert.Equal(t, test.expected, CPEString(c))
assert.Equal(t, test.expected, String(c))
})
}
}
@@ -222,13 +215,13 @@ func Test_RoundTrip(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
// CPE string must be preserved through a round trip
assert.Equal(t, test.cpe, CPEString(MustCPE(test.cpe)))
assert.Equal(t, test.cpe, String(Must(test.cpe)))
// The parsed CPE must be the same after a round trip
assert.Equal(t, MustCPE(test.cpe), MustCPE(CPEString(MustCPE(test.cpe))))
assert.Equal(t, Must(test.cpe), Must(String(Must(test.cpe))))
// The test case parsed CPE must be the same after parsing the input string
assert.Equal(t, test.parsedCPE, MustCPE(test.cpe))
assert.Equal(t, test.parsedCPE, Must(test.cpe))
// The test case parsed CPE must produce the same string as the input cpe
assert.Equal(t, CPEString(test.parsedCPE), test.cpe)
assert.Equal(t, String(test.parsedCPE), test.cpe)
})
}
}
@@ -1,10 +1,10 @@
package pkg
package cpe
import (
"sort"
)
func mergeCPEs(a, b []CPE) (result []CPE) {
func Merge(a, b []CPE) (result []CPE) {
aCPEs := make(map[string]CPE)
// keep all CPEs from a and create a quick string-based lookup
@@ -20,6 +20,6 @@ func mergeCPEs(a, b []CPE) (result []CPE) {
}
}
sort.Sort(CPEBySpecificity(result))
sort.Sort(BySpecificity(result))
return result
}
+41
View File
@@ -0,0 +1,41 @@
package cpe
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_Merge(t *testing.T) {
tests := []struct {
name string
input [][]CPE
expected []CPE
}{
{
name: "merge, removing duplicates and ordered",
input: [][]CPE{
{
Must("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
},
{
Must("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
},
},
expected: []CPE{
Must("cpe:2.3:a:some:package:1:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*"),
Must("cpe:2.3:a:*:package:1:*:*:*:*:*:*:*"),
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
out := Merge(test.input[0], test.input[1])
assert.Equal(t, test.expected, out)
})
}
}

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