Compare commits

...
101 Commits
Author SHA1 Message Date
Alan Pope bb952ed25a Draft: Identity proof - do NOT merge
Using this to prove my identity.

KJIc1D4zXJbRybKEJrWd

Signed-off-by: Alan Pope <alan.pope@anchore.com>
2024-08-07 08:12:41 +01:00
dependabot[bot] dcd87d1fef chore(deps): bump actions/upload-artifact from 4.3.4 to 4.3.5 (#3095)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.4 to 4.3.5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/0b2256b8c012f0828dc542b3febcab082c67f72b...89ef406dd8d7e03cfd12d9e0a4a378f454709029)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  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>
2024-08-06 13:17:36 -04:00
anchore-actions-token-generator[bot]andwagoodman 214a0498e0 chore(deps): update CPE dictionary index (#3094)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2024-08-06 13:07:48 -04:00
dependabot[bot] 0f9df805c1 chore(deps): bump golang.org/x/mod from 0.19.0 to 0.20.0 (#3096)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.19.0 to 0.20.0.
- [Commits](https://github.com/golang/mod/compare/v0.19.0...v0.20.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>
2024-08-06 13:07:33 -04:00
dependabot[bot] 703330abd0 chore(deps): bump github.com/gkampitakis/go-snaps from 0.5.6 to 0.5.7 (#3097)
Bumps [github.com/gkampitakis/go-snaps](https://github.com/gkampitakis/go-snaps) from 0.5.6 to 0.5.7.
- [Release notes](https://github.com/gkampitakis/go-snaps/releases)
- [Commits](https://github.com/gkampitakis/go-snaps/compare/v0.5.6...v0.5.7)

---
updated-dependencies:
- dependency-name: github.com/gkampitakis/go-snaps
  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>
2024-08-06 13:07:21 -04:00
Gijs CalisandKeith Zantow 9d40d1152e feat: improved java maven property resolution (#2769)
Signed-off-by: Gijs Calis <51088038+GijsCalis@users.noreply.github.com>
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2024-08-05 11:30:47 -04:00
Harippriya Sivapatham cc15edca62 fix: use organization for package supplier when reading Java vendor fields (#3093)
Signed-off-by: Harippriya Sivapatham <harippriyasivapatham@gmail.com>
2024-08-03 16:00:55 -04:00
anchore-actions-token-generator[bot]andspiffcs 623532e3ed chore(deps): update tools to latest versions (#3091)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-08-02 13:25:09 -04:00
Dor Hayunanddor-hayun 48f1e975f0 fix: update 'guessMainPackageNameAndVersionFromPomInfo' and 'artifactIDMatchesFilename' (#3054)
- Correct retrieval of package name when main POM file exists
- Address issue where wrong package name was retrieved for certain jars
- Example case: 'jansi' jar containing multiple jars like 'jansi-win32'
- Ensure true is returned when filename matches the artifact ID, prevent random retrieval by checking prefix and suffix
- Use fallback check with suffix and prefix if no POM properties file matches the exact artifact name

Signed-off-by: dor-hayun <dor.hayun@mend.io>
Co-authored-by: dor-hayun <dor.hayun@mend.io>
2024-08-01 13:47:15 -04:00
Christopher Angelo Phillips c84cb2cf84 fix: update mainModuleVersion function to always prefix v to findings (#3087)
* chore: basic fix
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
* test: make sure ldflags are prefixed with v
---------
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2024-08-01 11:29:07 -04:00
Keith Zantow 05a10e8bed chore: update release script to use gh from binny (#3084)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-07-31 20:10:17 -04:00
Laurent Goderre 92d63df6f5 Added the SWI Prolog (swipl) ecosystem (#3076)
* Add binary classifier for swipl

Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>

* Added cataloger for SWI Prolog Pack packages

Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>

---------

Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
2024-07-31 16:13:26 -04:00
Keith Zantow a4b5dcd0df fix: improve determinism in java archive identification (#3085)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-07-30 12:02:52 -04:00
anchore-actions-token-generator[bot]andkzantow 06526e2931 chore(deps): update stereoscope to 50ce3be7aa1fb8829234ae648215e7907196bfa5 (#3075)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kzantow <3009477+kzantow@users.noreply.github.com>
2024-07-29 10:04:46 -04:00
anchore-actions-token-generator[bot]andwagoodman a2042e629c chore(deps): update CPE dictionary index (#3079)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2024-07-29 10:03:59 -04:00
dependabot[bot] a35e410c75 chore(deps): bump github.com/gkampitakis/go-snaps from 0.5.5 to 0.5.6 (#3082)
Bumps [github.com/gkampitakis/go-snaps](https://github.com/gkampitakis/go-snaps) from 0.5.5 to 0.5.6.
- [Release notes](https://github.com/gkampitakis/go-snaps/releases)
- [Commits](https://github.com/gkampitakis/go-snaps/compare/v0.5.5...v0.5.6)

---
updated-dependencies:
- dependency-name: github.com/gkampitakis/go-snaps
  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>
2024-07-29 10:03:44 -04:00
dependabot[bot] 8dd7c9c0b9 chore(deps): bump github/codeql-action from 3.25.14 to 3.25.15 (#3083)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.25.14 to 3.25.15.
- [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/5cf07d8b700b67e235fbb65cbc84f69c0cf10464...afb54ba388a7dca6ecae48f608c4ff05ff4cc77a)

---
updated-dependencies:
- dependency-name: github/codeql-action
  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>
2024-07-29 10:03:35 -04:00
witchcraze 490e05adb2 fix: traefik classifier (#3077)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2024-07-29 09:46:51 -04:00
mikcl 1cd75b7d68 python-cataloger: fix normalization test (#3073)
Signed-off-by: mikcl <mikesmikes400@gmail.com>
2024-07-25 15:45:14 -04:00
Laurent Goderre 4882d2e8ce Only match ldflag version if it matches the main module or targets main.version (#3062)
Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
2024-07-25 13:56:55 -04:00
mikcl b3848f780f python cataloger: allow dots in python package names (#3070)
Signed-off-by: mikcl <mikesmikes400@gmail.com>
2024-07-25 13:56:10 -04:00
mikcl 36f95d6828 python-cataloger: normalize package names (#3069)
Signed-off-by: mikcl <mikesmikes400@gmail.com>
2024-07-25 13:54:13 -04:00
dependabot[bot] 68b96ae444 chore(deps): bump github.com/docker/docker (#3066)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 27.1.0+incompatible to 27.1.1+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v27.1.0...v27.1.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>
2024-07-25 13:50:33 -04:00
dependabot[bot] 3917989f86 chore(deps): bump github/codeql-action from 3.25.13 to 3.25.14 (#3072)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.25.13 to 3.25.14.
- [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/2d790406f505036ef40ecba973cc774a50395aac...5cf07d8b700b67e235fbb65cbc84f69c0cf10464)

---
updated-dependencies:
- dependency-name: github/codeql-action
  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>
2024-07-25 13:50:06 -04:00
Keith Zantow 741c8fb9bd fix: SPDX output performance with many relationships (#3053) 2024-07-24 10:14:20 -04:00
Alex Goodman 9573f557d1 better go mod detection from partial package builds (#3060)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-07-24 09:34:40 -04:00
anchore-actions-token-generator[bot]andspiffcs ca945d16e0 chore(deps): update tools to latest versions (#3061)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-07-23 10:16:25 -04:00
dependabot[bot]andChristopher Phillips fe7c5a7174 chore(deps): bump github.com/charmbracelet/lipgloss from 0.11.1 to 0.12.1 (#3040)
* chore(deps): bump github.com/charmbracelet/lipgloss

Bumps [github.com/charmbracelet/lipgloss](https://github.com/charmbracelet/lipgloss) from 0.11.1 to 0.12.1.
- [Release notes](https://github.com/charmbracelet/lipgloss/releases)
- [Changelog](https://github.com/charmbracelet/lipgloss/blob/master/.goreleaser.yml)
- [Commits](https://github.com/charmbracelet/lipgloss/compare/v0.11.1...v0.12.1)

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

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

* chore: pin fedora linux/amd64 to sha

Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
Signed-off-by: Christopher Angelo Phillips <32073428+spiffcs@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2024-07-22 10:43:17 -07:00
Keith Zantow 125c787e40 chore: add debug logging for errors reading RPM files (#3051)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-07-22 13:05:04 -04:00
anchore-actions-token-generator[bot]andwagoodman bfe6f5204a chore(deps): update CPE dictionary index (#3035)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2024-07-22 08:56:58 -07:00
dependabot[bot] aead40e1de chore(deps): bump github.com/docker/docker (#3055)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 27.0.3+incompatible to 27.1.0+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v27.0.3...v27.1.0)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  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>
2024-07-22 08:56:01 -07:00
dependabot[bot] 536611fa25 chore(deps): bump github.com/gkampitakis/go-snaps from 0.5.4 to 0.5.5 (#3056)
Bumps [github.com/gkampitakis/go-snaps](https://github.com/gkampitakis/go-snaps) from 0.5.4 to 0.5.5.
- [Release notes](https://github.com/gkampitakis/go-snaps/releases)
- [Commits](https://github.com/gkampitakis/go-snaps/compare/v0.5.4...v0.5.5)

---
updated-dependencies:
- dependency-name: github.com/gkampitakis/go-snaps
  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>
2024-07-22 08:45:25 -07:00
dependabot[bot] d0a7d4c43e chore(deps): bump modernc.org/sqlite from 1.30.2 to 1.31.1 (#3057)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.30.2 to 1.31.1.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.30.2...v1.31.1)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  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>
2024-07-22 08:45:01 -07:00
dependabot[bot] 0c53a087f0 chore(deps): bump docker/login-action from 3.2.0 to 3.3.0 (#3058)
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.2.0 to 3.3.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/0d4c9c5ea7693da7b068278f7b52bda2a190a446...9780b0c442fbb1117ed29e0efdff1e18412f7567)

---
updated-dependencies:
- dependency-name: docker/login-action
  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>
2024-07-22 08:44:06 -07:00
dependabot[bot] b263b1ec1f chore(deps): bump github/codeql-action from 3.25.12 to 3.25.13 (#3059)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.25.12 to 3.25.13.
- [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/4fa2a7953630fd2f3fb380f21be14ede0169dd4f...2d790406f505036ef40ecba973cc774a50395aac)

---
updated-dependencies:
- dependency-name: github/codeql-action
  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>
2024-07-22 10:55:55 -04:00
034a98f029 chore(deps): update stereoscope to 487b11e5ba2622d976acda10c605da63b4fbbb0a (#3032)
* chore(deps): update stereoscope to 487b11e5ba2622d976acda10c605da63b4fbbb0a

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* chore: allow unlicense

Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
Co-authored-by: kzantow <3009477+kzantow@users.noreply.github.com>
Co-authored-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2024-07-18 09:26:01 -07:00
anchore-actions-token-generator[bot]andspiffcs 69031b0646 chore(deps): update tools to latest versions (#3050)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-07-18 08:21:31 -07:00
Alan Pope 761a161e7f docs: CODE_OF_CONDUCT.md (#3046)
This PR adds a code of conduct document to the repo, as agreed at our recent OSS team catch up.

Signed-off-by: Alan Pope <alan@popey.com>
2024-07-17 14:33:17 -07:00
Keith Zantow ba31c2f1ae fix: include CPEs with Maven groupId as vendor (#3045)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-07-17 11:23:58 -07:00
dependabot[bot] 5d729a5e9e chore(deps): bump github.com/google/go-containerregistry (#3047)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.20.0 to 0.20.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.20.0...v0.20.1)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  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>
2024-07-17 11:21:23 -07:00
dependabot[bot] 276df95768 chore(deps): bump github.com/moby/sys/mountinfo from 0.7.1 to 0.7.2 (#3048)
Bumps [github.com/moby/sys/mountinfo](https://github.com/moby/sys) from 0.7.1 to 0.7.2.
- [Release notes](https://github.com/moby/sys/releases)
- [Commits](https://github.com/moby/sys/compare/signal/v0.7.1...mountinfo/v0.7.2)

---
updated-dependencies:
- dependency-name: github.com/moby/sys/mountinfo
  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>
2024-07-17 11:21:14 -07:00
dependabot[bot] cca9a06a64 chore(deps): bump modernc.org/sqlite from 1.30.1 to 1.30.2 (#3039)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.30.1 to 1.30.2.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.30.1...v1.30.2)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  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>
2024-07-17 09:10:34 -04:00
Bradley Jones 4d23990dd4 docs: link to contrib/dev docs in readme (#3029)
These docs are full of great information so make them easily accessible
from the README so they aren't overlooked.

Signed-off-by: Bradley Jones <bradley.jones@anchore.com>
2024-07-16 06:59:31 -07:00
Adam McClenaghan d4fa61e0a2 chore: Fix apache shield in readme (#3021)
Signed-off-by: Adam McClenaghan <adam@mcclenaghan.co.uk>
2024-07-16 06:59:14 -07:00
anchore-actions-token-generator[bot]andspiffcs d4d4e003e9 chore(deps): update tools to latest versions (#3031)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-07-16 06:58:33 -07:00
dependabot[bot] 6bf91a410d chore(deps): bump github/codeql-action from 3.25.11 to 3.25.12 (#3034)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.25.11 to 3.25.12.
- [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/b611370bb5703a7efb587f9d136a52ea24c5c38c...4fa2a7953630fd2f3fb380f21be14ede0169dd4f)

---
updated-dependencies:
- dependency-name: github/codeql-action
  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>
2024-07-16 06:58:18 -07:00
dependabot[bot] 77c300d617 chore(deps): bump anchore/sbom-action from 0.16.1 to 0.17.0 (#3044)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.16.1 to 0.17.0.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/95b086ac308035dc0850b3853be5b7ab108236a8...d94f46e13c6c62f59525ac9a1e147a99dc0b9bf5)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  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>
2024-07-16 06:58:07 -07:00
William Murphy 75902b0540 fix: stop panicking on "devel" version go stdlib (#3043)
Previously, if a Go binary was cataloged with build info indicating that
the go compiler version used was "deve", syft would panic on a nil
pointer dereference. Instead, skip creating a Go stdlib reference and
relationship for such a package.

Signed-off-by: Will Murphy <will.murphy@anchore.com>
2024-07-16 09:51:14 -04:00
Keith Zantow 278b72d39b chore: pin fedora image for elf binary test (#3041)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-07-15 16:37:09 +00:00
dependabot[bot] 37245a21cc chore(deps): bump anchore/sbom-action from 0.16.0 to 0.16.1 (#3023)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.16.0 to 0.16.1.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/e8d2a6937ecead383dfe75190d104edd1f9c5751...95b086ac308035dc0850b3853be5b7ab108236a8)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  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>
2024-07-11 14:50:48 -04:00
anchore-actions-token-generator[bot]andkzantow e2fe955262 chore(deps): update stereoscope to 27b66b76fc6686fcf6bde656aa09e1f0e047fec1 (#3026)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kzantow <3009477+kzantow@users.noreply.github.com>
2024-07-11 10:38:10 -07:00
dependabot[bot] 4e09908ba1 chore(deps): bump actions/setup-go from 5.0.1 to 5.0.2 (#3027)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.0.1 to 5.0.2.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/cdcb36043654635271a94b9a6d1392de5bb323a7...0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32)

---
updated-dependencies:
- dependency-name: actions/setup-go
  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>
2024-07-11 10:19:48 -07:00
dependabot[bot] 863793a3cc chore(deps): bump github.com/charmbracelet/lipgloss (#3028)
Bumps [github.com/charmbracelet/lipgloss](https://github.com/charmbracelet/lipgloss) from 0.11.0 to 0.11.1.
- [Release notes](https://github.com/charmbracelet/lipgloss/releases)
- [Changelog](https://github.com/charmbracelet/lipgloss/blob/master/.goreleaser.yml)
- [Commits](https://github.com/charmbracelet/lipgloss/compare/v0.11.0...v0.11.1)

---
updated-dependencies:
- dependency-name: github.com/charmbracelet/lipgloss
  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>
2024-07-11 10:19:14 -07:00
Christopher Angelo Phillips f7ffcc534f fix: stabilize cpe sorting during collection sort (#3009) 2024-07-09 14:24:21 -04:00
Laurent Goderre b101f44aba Map the downloadLocation field for PHP Composer packages (#3011)
Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
2024-07-09 09:01:58 -07:00
anchore-actions-token-generator[bot]andkzantow de3313cfb6 chore(deps): update stereoscope to e46739e217969fa67cbe8834b64bb165a10a1548 (#3013)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kzantow <3009477+kzantow@users.noreply.github.com>
2024-07-09 07:53:04 -07:00
dependabot[bot] b2f9904d74 chore(deps): bump golang.org/x/net from 0.26.0 to 0.27.0 (#3015)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/net/compare/v0.26.0...v0.27.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>
2024-07-09 07:52:32 -07:00
dependabot[bot] 13d01ecaff chore(deps): bump golang.org/x/mod from 0.18.0 to 0.19.0 (#3014)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.18.0 to 0.19.0.
- [Commits](https://github.com/golang/mod/compare/v0.18.0...v0.19.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>
2024-07-09 07:08:25 -07:00
dependabot[bot] 7dc1b1ce27 chore(deps): bump actions/upload-artifact from 4.3.3 to 4.3.4 (#3017)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.3 to 4.3.4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/65462800fd760344b1a7b4382951275a0abb4808...0b2256b8c012f0828dc542b3febcab082c67f72b)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  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>
2024-07-09 07:08:12 -07:00
dependabot[bot] b8dce675fe chore(deps): bump github.com/google/go-containerregistry (#3019)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.19.2 to 0.20.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.19.2...v0.20.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>
2024-07-09 07:08:02 -07:00
dependabot[bot] 6dda9edd7c chore(deps): bump github.com/adrg/xdg from 0.4.0 to 0.5.0 (#3020)
Bumps [github.com/adrg/xdg](https://github.com/adrg/xdg) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/adrg/xdg/releases)
- [Commits](https://github.com/adrg/xdg/compare/v0.4.0...v0.5.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>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-09 07:07:53 -07:00
anchore-actions-token-generator[bot] 04c861bf77 chore(deps): update CPE dictionary index (#3016) 2024-07-08 08:13:17 -04:00
Alex Goodman 573440b7cf Infer the package type from ELF package notes (#3008)
* fix ELF package types to be honored

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* prefer OS packages over binary packages when there are duplicates

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-07-02 16:07:08 -04:00
anchore-actions-token-generator[bot] c816039e91 chore(deps): update tools to latest versions (#3003) 2024-07-01 20:04:45 -04:00
anchore-actions-token-generator[bot] 7f3ca65cf6 chore(deps): update CPE dictionary index (#3002) 2024-07-01 15:02:15 -04:00
dependabot[bot] 43e5b1b45f chore(deps): bump github.com/docker/docker (#3006) 2024-07-01 19:01:01 +00:00
dependabot[bot] a876aaccb2 chore(deps): bump github/codeql-action from 3.25.10 to 3.25.11 (#3004) 2024-07-01 19:00:35 +00:00
dependabot[bot] 875669bfd1 chore(deps): bump github.com/saferwall/pe from 1.5.3 to 1.5.4 (#3005) 2024-07-01 19:00:07 +00:00
Danielle Featherstone 5283c4687a feat: version 3 support for swift package manager of the resolved files (#3001)
Signed-off-by: Danielle Featherstone <dfeatherstone@fearless.tech>
2024-07-01 14:27:37 -04:00
dependabot[bot] 4d48adfa3f chore(deps): bump github.com/spdx/tools-golang from 0.5.4 to 0.5.5 (#2999) 2024-06-26 13:44:52 +00:00
dependabot[bot] c8b449c92b chore(deps): bump github.com/docker/docker (#2994)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 26.1.4+incompatible to 27.0.1+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v26.1.4...v27.0.1)

---
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>
2024-06-25 14:40:51 -07:00
Laurent Goderre ceced5eb27 Add detection of Erlang in Alpine linux (#2996)
Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
2024-06-25 14:40:40 -07:00
anchore-actions-token-generator[bot]andspiffcs 7da15890eb chore(deps): update tools to latest versions (#2991)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-06-25 13:41:26 -07:00
anchore-actions-token-generator[bot]andkzantow 580c09b01c chore(deps): update stereoscope to 753b5576fe42bc007b22108ad7911d1729957a46 (#2992)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kzantow <3009477+kzantow@users.noreply.github.com>
2024-06-25 13:41:08 -07:00
dependabot[bot] 0dce67872e chore(deps): bump github.com/charmbracelet/bubbletea (#2995)
Bumps [github.com/charmbracelet/bubbletea](https://github.com/charmbracelet/bubbletea) from 0.26.5 to 0.26.6.
- [Release notes](https://github.com/charmbracelet/bubbletea/releases)
- [Changelog](https://github.com/charmbracelet/bubbletea/blob/master/.goreleaser.yml)
- [Commits](https://github.com/charmbracelet/bubbletea/compare/v0.26.5...v0.26.6)

---
updated-dependencies:
- dependency-name: github.com/charmbracelet/bubbletea
  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>
2024-06-25 10:10:26 -07:00
anchore-actions-token-generator[bot]andwagoodman 1eae9333a9 chore(deps): update CPE dictionary index (#2986)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2024-06-24 08:27:29 -07:00
dependabot[bot] 863891f325 chore(deps): bump github.com/go-test/deep from 1.1.0 to 1.1.1 (#2988)
Bumps [github.com/go-test/deep](https://github.com/go-test/deep) from 1.1.0 to 1.1.1.
- [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.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: github.com/go-test/deep
  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>
2024-06-24 08:27:13 -07:00
Keith Zantow bd1c1d260c fix: handle errors reading go licenses (#2985)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-06-24 10:27:03 -04:00
Christopher Angelo Phillips f5a917a5a2 docs: update cyclone-dx documentation (#2983)
* chore: update docs to show 1.6 for cyclone-dx by default
* chore: update README showing version information for formats

---------

Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2024-06-21 09:32:59 -07:00
Rajan Agaskar ae0683074e feat: update syft to generate cyclone-dx 1.6 by default (#2978)
- Resolves #2974
- add detailed instructions re: updating schemas (a necessary task
  when a new CycloneDX spec version becomes available).
- The DefaultVersion constant has been updated to "1.6" -- it's not
  clear to me how this is used at this time (it may be redundant given
  other code), but effectively unless a specific spec version is
  configured, `syft` will emit the "most recent" spec version available
  for cyclonedx. Users who wish to pin back to a "older" specVersion
  (e.g. to preserve compatibilty with utilities that have not yet bumped
  to latest) can either set this in a syft config file or pass a
  name@spec_version pair to the output flag (e.g. `-o
  cyclonedx-json@1.5=some-1.5-spec-bom.cdx.json`)
- Regenerate relevant .golden files (there seems to be a way to do this
  via flags, but I couldn't quite figure out the right set to pass
  correctly, esp. since (as a relative go novice) I found it difficult
  to run just a single test file. I ended up "brute-forcing it" by
  changing the *updateSnapshot val to "true" and running it in Goland.
  A brief comment giving an example of regenerating fixtures usage would
  be helpful.

Signed-off-by: Rajan Agaskar <ragaskar@gmail.com>
2024-06-21 08:51:27 -07:00
dependabot[bot] 9b178174a7 chore(deps): bump github.com/charmbracelet/bubbletea (#2982)
Bumps [github.com/charmbracelet/bubbletea](https://github.com/charmbracelet/bubbletea) from 0.26.4 to 0.26.5.
- [Release notes](https://github.com/charmbracelet/bubbletea/releases)
- [Changelog](https://github.com/charmbracelet/bubbletea/blob/master/.goreleaser.yml)
- [Commits](https://github.com/charmbracelet/bubbletea/compare/v0.26.4...v0.26.5)

---
updated-dependencies:
- dependency-name: github.com/charmbracelet/bubbletea
  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>
2024-06-21 08:46:35 -07:00
dependabot[bot] e947779886 chore(deps): bump peter-evans/create-pull-request from 6.0.5 to 6.1.0 (#2975) 2024-06-20 15:12:12 +00:00
Laurent Goderre 7a35de04ee fix: detection of arangodb 3.12 (#2979)
Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
2024-06-20 11:11:03 -04:00
Weston Steimel 246df97ae7 chore: enable dependabot to keep boostrap action updated (#2976)
Signed-off-by: Weston Steimel <commits@weston.slmail.me>
2024-06-19 20:17:11 +01:00
dependabot[bot] 750d37f075 chore(deps): bump github.com/github/go-spdx/v2 from 2.2.0 to 2.3.1 (#2973)
Bumps [github.com/github/go-spdx/v2](https://github.com/github/go-spdx) from 2.2.0 to 2.3.1.
- [Release notes](https://github.com/github/go-spdx/releases)
- [Commits](https://github.com/github/go-spdx/compare/v2.2.0...v2.3.1)

---
updated-dependencies:
- dependency-name: github.com/github/go-spdx/v2
  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>
2024-06-18 09:46:11 -07:00
dependabot[bot] 5061b905dc chore(deps): bump github.com/google/go-containerregistry (#2971)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.19.1 to 0.19.2.
- [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.19.1...v0.19.2)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  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>
2024-06-17 08:44:19 -07:00
dependabot[bot] ed3774afa7 chore(deps): bump github.com/spf13/cobra from 1.8.0 to 1.8.1 (#2972)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.0...v1.8.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>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 08:44:10 -07:00
Christopher Angelo PhillipsandAlex Goodman 22d5731482 fix: fix parsing for complex toml types (#2965)
* fix: fix parsing for complex toml types
---------
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-06-14 19:32:17 +00:00
Keith Zantow af3aaa0397 fix: make caching options more explicit (#2966)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-06-14 18:45:48 +00:00
anchore-actions-token-generator[bot]andspiffcs 70098e20bb chore(deps): update tools to latest versions (#2961)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-06-14 08:18:41 -07:00
dependabot[bot] 784b17f66c chore(deps): bump github/codeql-action from 3.25.9 to 3.25.10 (#2964)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.25.9 to 3.25.10.
- [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/530d4feaa9c62aaab2d250371e2061eb7a172363...23acc5c183826b7a8a97bce3cecc52db901f8251)

---
updated-dependencies:
- dependency-name: github/codeql-action
  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>
2024-06-14 08:18:25 -07:00
Weston Steimel d5cd5f6091 feat: index known CPEs for wordpress plugins and themes (#2963)
Signed-off-by: Weston Steimel <commits@weston.slmail.me>
2024-06-14 14:39:43 +01:00
Weston SteimelandAlex Goodman 749ccc59c1 fix(golang): improve version extraction from ldflags for pingcap TiDB (#2962)
* fix(golang): improve version extraction from ldflags for pingcap TiDB

Signed-off-by: Weston Steimel <commits@weston.slmail.me>

* loosen ld flag parsing requirements

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Weston Steimel <commits@weston.slmail.me>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-06-14 14:35:14 +01:00
dependabot[bot] 273e31e806 chore(deps): bump actions/checkout from 4.1.6 to 4.1.7 (#2955)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.6 to 4.1.7.
- [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/a5ac7e51b41094c92402da3b24376905380afc29...692973e3d937129bcbf40652eb9f2f61becf3332)

---
updated-dependencies:
- dependency-name: actions/checkout
  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>
2024-06-13 12:28:04 -04:00
dependabot[bot] 9beaec2e97 chore(deps): bump github/codeql-action from 3.25.8 to 3.25.9 (#2956)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.25.8 to 3.25.9.
- [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/2e230e8fe0ad3a14a340ad0815ddb96d599d2aff...530d4feaa9c62aaab2d250371e2061eb7a172363)

---
updated-dependencies:
- dependency-name: github/codeql-action
  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>
2024-06-13 12:27:53 -04:00
Keith Zantow ca0cc52d47 fix: separate golang license caches from mod dir (#2852)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-06-12 19:12:35 -04:00
dependabot[bot] dd723bb3c5 chore(deps): bump github.com/vbatts/go-mtree from 0.5.3 to 0.5.4 (#2952)
Bumps [github.com/vbatts/go-mtree](https://github.com/vbatts/go-mtree) from 0.5.3 to 0.5.4.
- [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.3...v0.5.4)

---
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>
2024-06-12 13:17:06 -04:00
anchore-actions-token-generator[bot]andspiffcs fb68489590 chore(deps): update tools to latest versions (#2949)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-06-11 08:09:07 -07:00
dependabot[bot] 5590d5c1ce chore(deps): bump modernc.org/sqlite from 1.30.0 to 1.30.1 (#2950)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.30.0 to 1.30.1.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.30.0...v1.30.1)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  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>
2024-06-11 08:08:45 -07:00
Alex Goodman 0956753409 Consider Author field for wordpress plugins when generating CPEs (#2946)
* enhance wordpress vendor candidates for CPEs

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* encode wordpress plugin target software

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-06-10 14:12:20 -04:00
Alex Goodman f966bcfd03 trim whitespace from wordpress values (#2945)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-06-10 13:35:01 -04:00
186 changed files with 26929 additions and 2632 deletions
+5 -5
View File
@@ -18,7 +18,7 @@ tools:
# used to sign mac binaries at release
- name: quill
version:
want: v0.4.1
want: v0.4.2
method: github-release
with:
repo: anchore/quill
@@ -42,7 +42,7 @@ tools:
# used for signing the checksums file at release
- name: cosign
version:
want: v2.2.4
want: v2.3.0
method: github-release
with:
repo: sigstore/cosign
@@ -58,7 +58,7 @@ tools:
# used to release all artifacts
- name: goreleaser
version:
want: v2.0.0
want: v2.1.0
method: github-release
with:
repo: goreleaser/goreleaser
@@ -103,7 +103,7 @@ tools:
# used for running all local and CI tasks
- name: task
version:
want: v3.37.2
want: v3.38.0
method: github-release
with:
repo: go-task/task
@@ -111,7 +111,7 @@ tools:
# used for triggering a release
- name: gh
version:
want: v2.50.0
want: v2.54.0
method: github-release
with:
repo: cli/cli
+1
View File
@@ -6,6 +6,7 @@ permit:
- MPL.*
- ISC
- WTFPL
- Unlicense
ignore-packages:
# packageurl-go is released under the MIT license located in the root of the repo at /mit.LICENSE
+2 -2
View File
@@ -27,14 +27,14 @@ runs:
using: "composite"
steps:
# note: go mod and build is automatically cached on default with v4+
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 #v5.0.1
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
if: inputs.go-version != ''
with:
go-version: ${{ inputs.go-version }}
- name: Restore tool cache
id: tool-cache
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
with:
path: ${{ github.workspace }}/.tool
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('.binny.yaml') }}
+8
View File
@@ -17,3 +17,11 @@ updates:
open-pull-requests-limit: 10
labels:
- "dependencies"
- package-ecosystem: "github-actions"
directory: "/.github/actions/boostrap"
schedule:
interval: "daily"
open-pull-requests-limit: 10
labels:
- "dependencies"
+14 -7
View File
@@ -4,12 +4,19 @@ 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"
GH_CLI=.tool/gh
if ! [ -x "$(command -v $GH_CLI)" ]; then
echo "The GitHub CLI could not be found. run: make bootstrap"
exit 1
fi
gh auth status
$GH_CLI auth status
# set the default repo in cases where multiple remotes are defined
$GH_CLI repo set-default anchore/syft
export GITHUB_TOKEN="${GITHUB_TOKEN-"$($GH_CLI auth token)"}"
# 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.
@@ -37,7 +44,7 @@ done
echo "${bold}Kicking off release for ${NEXT_VERSION}${normal}..."
echo
gh workflow run release.yaml -f version=${NEXT_VERSION}
$GH_CLI workflow run release.yaml -f version=${NEXT_VERSION}
echo
echo "${bold}Waiting for release to start...${normal}"
@@ -45,6 +52,6 @@ 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)
echo "${bold}Head to the release workflow to monitor the release:${normal} $($GH_CLI run list --workflow=release.yaml --limit=1 --json url --jq '.[].url')"
id=$($GH_CLI run list --workflow=release.yaml --limit=1 --json databaseId --jq '.[].databaseId')
$GH_CLI run watch $id --exit-status || (echo ; echo "${bold}Logs of failed step:${normal}" && GH_PAGER="" $GH_CLI run view $id --log-failed)
+2 -2
View File
@@ -17,7 +17,7 @@ jobs:
# the job by event.
steps:
- name: Checkout code
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -39,7 +39,7 @@ jobs:
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
echo "result=$OUTPUT" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
- uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # v4.3.5
with:
name: benchmark-test-results
path: test/results/**/*
+5 -5
View File
@@ -36,16 +36,16 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Install Go
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 #v5.0.1
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 #v5.0.2
with:
go-version-file: go.mod
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff #v3.25.8
uses: github/codeql-action/init@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a #v3.25.15
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -56,7 +56,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@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff #v3.25.8
uses: github/codeql-action/autobuild@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a #v3.25.15
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -70,4 +70,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff #v3.25.8
uses: github/codeql-action/analyze@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a #v3.25.15
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- run: python .github/scripts/labeler.py
env:
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
release:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Update version file
run: make ci-release-version-file
+5 -5
View File
@@ -15,7 +15,7 @@ jobs:
environment: release
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Check if running on main
if: github.ref != 'refs/heads/main'
@@ -105,7 +105,7 @@ jobs:
# required for goreleaser signs section with cosign
id-token: write
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
with:
fetch-depth: 0
@@ -113,13 +113,13 @@ jobs:
uses: ./.github/actions/bootstrap
- name: Login to Docker Hub
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 #v3.2.0
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 #v3.3.0
with:
username: ${{ secrets.ANCHOREOSSWRITE_DH_USERNAME }}
password: ${{ secrets.ANCHOREOSSWRITE_DH_PAT }}
- name: Login to GitHub Container Registry
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 #v3.2.0
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 #v3.3.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -148,7 +148,7 @@ jobs:
# for updating brew formula in anchore/homebrew-syft
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
- uses: anchore/sbom-action@e8d2a6937ecead383dfe75190d104edd1f9c5751 #v0.16.0
- uses: anchore/sbom-action@d94f46e13c6c62f59525ac9a1e147a99dc0b9bf5 #v0.17.0
continue-on-error: true
with:
artifact-name: sbom.spdx.json
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'anchore/syft' # only run for main repo
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -50,7 +50,7 @@ jobs:
app_id: ${{ secrets.TOKEN_APP_ID }}
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
- uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e #v6.0.5
- uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c #v6.1.0
with:
signoff: true
delete-branch: true
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'anchore/syft' # only run for main repo
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -33,7 +33,7 @@ jobs:
app_id: ${{ secrets.TOKEN_APP_ID }}
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
- uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e #v6.0.5
- uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c #v6.1.0
with:
signoff: true
delete-branch: true
@@ -17,9 +17,9 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'anchore/syft' # only run for main repo
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 #v5.0.1
- uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 #v5.0.2
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
@@ -44,7 +44,7 @@ jobs:
app_id: ${{ secrets.TOKEN_APP_ID }}
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
- uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e #v6.0.5
- uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c #v6.1.0
with:
signoff: true
delete-branch: true
+7 -7
View File
@@ -17,7 +17,7 @@ jobs:
name: "Static analysis"
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -31,7 +31,7 @@ jobs:
name: "Unit tests"
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -87,7 +87,7 @@ jobs:
name: "Integration tests"
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -109,7 +109,7 @@ jobs:
name: "Build snapshot artifacts"
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -139,7 +139,7 @@ jobs:
needs: [Build-Snapshot-Artifacts]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -190,7 +190,7 @@ jobs:
- name: Install Cosign
uses: sigstore/cosign-installer@v3.5.0
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -234,7 +234,7 @@ jobs:
needs: [Build-Snapshot-Artifacts]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.1.7
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
+128
View File
@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[opensource@anchore.com](mailto:opensource@anchore.com).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+13 -3
View File
@@ -11,7 +11,7 @@
&nbsp;<a href="https://goreportcard.com/report/github.com/anchore/syft" target="_blank"><img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/anchore/syft"></a>&nbsp;
&nbsp;<a href="https://github.com/anchore/syft/releases/latest" target="_blank"><img alt="GitHub release" src="https://img.shields.io/github/release/anchore/syft.svg"></a>&nbsp;
&nbsp;<a href="https://github.com/anchore/syft" target="_blank"><img alt="GitHub go.mod Go version" src="https://img.shields.io/github/go-mod/go-version/anchore/syft.svg"></a>&nbsp;
&nbsp;<a href"" target="_blank"><img alt="License: Apache-2.0" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a>&nbsp;
&nbsp;<a href="" target="_blank"><img alt="License: Apache-2.0" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a>&nbsp;
&nbsp;<a href="https://anchore.com/slack" target="_blank"><img alt="Slack" src="https://img.shields.io/badge/Slack-Join-blue?logo=slack"></a>&nbsp;
</p>
@@ -105,8 +105,10 @@ syft <image> -o <format>
Where the `formats` available are:
- `syft-json`: Use this to get as much information out of Syft as possible!
- `syft-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/).
- `cyclonedx-xml`: A XML report conforming to the [CycloneDX 1.6 specification](https://cyclonedx.org/specification/overview/).
- `cyclonedx-xml@1.5`: A XML report conforming to the [CycloneDX 1.5 specification](https://cyclonedx.org/specification/overview/).
- `cyclonedx-json`: A JSON report conforming to the [CycloneDX 1.6 specification](https://cyclonedx.org/specification/overview/).
- `cyclonedx-json@1.5`: A JSON report conforming to the [CycloneDX 1.5 specification](https://cyclonedx.org/specification/overview/).
- `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).
@@ -115,6 +117,8 @@ Where the `formats` available are:
- `syft-table`: A columnar summary (default).
- `template`: Lets the user specify the output format. See ["Using templates"](#using-templates) below.
Note that flags using the @<version> can be used for earlier versions of each specification as well.
### Supported Ecosystems
- Alpine (apk)
@@ -164,9 +168,15 @@ Our [wiki](https://github.com/anchore/syft/wiki) contains further details on the
* [Adding an SBOM to an image as an attestation using Syft](https://github.com/anchore/syft/wiki/attestation#adding-an-sbom-to-an-image-as-an-attestation-using-syft)
* [Configuration](https://github.com/anchore/syft/wiki/configuration)
## Contributing
Check out our [contributing](/CONTRIBUTING.md) guide and [developer](/DEVELOPING.md) docs.
## Syft Team Meetings
The Syft Team hold regular community meetings online. All are welcome to join to bring topics for discussion.
- Check the [calendar](https://calendar.google.com/calendar/u/0/r?cid=Y182OTM4dGt0MjRtajI0NnNzOThiaGtnM29qNEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t) for the next meeting date.
- Add items to the [agenda](https://docs.google.com/document/d/1ZtSAa6fj2a6KRWviTn3WoJm09edvrNUp4Iz_dOjjyY8/edit?usp=sharing) (join [this group](https://groups.google.com/g/anchore-oss-community) for write access to the [agenda](https://docs.google.com/document/d/1ZtSAa6fj2a6KRWviTn3WoJm09edvrNUp4Iz_dOjjyY8/edit?usp=sharing))
- See you there!
<!-- KJIc1D4zXJbRybKEJrWd -->
+2
View File
@@ -43,6 +43,7 @@ type attestOptions struct {
options.UpdateCheck `yaml:",inline" mapstructure:",squash"`
options.Catalog `yaml:",inline" mapstructure:",squash"`
Attest options.Attest `yaml:"attest" mapstructure:"attest"`
Cache options.Cache `json:"-" yaml:"cache" mapstructure:"cache"`
}
func Attest(app clio.Application) *cobra.Command {
@@ -77,6 +78,7 @@ func defaultAttestOptions() attestOptions {
Output: defaultAttestOutputOptions(),
UpdateCheck: options.DefaultUpdateCheck(),
Catalog: options.DefaultCatalog(),
Cache: options.DefaultCache(),
}
}
+2
View File
@@ -68,6 +68,7 @@ type scanOptions struct {
options.Output `yaml:",inline" mapstructure:",squash"`
options.UpdateCheck `yaml:",inline" mapstructure:",squash"`
options.Catalog `yaml:",inline" mapstructure:",squash"`
Cache options.Cache `json:"-" yaml:"cache" mapstructure:"cache"`
}
func defaultScanOptions() *scanOptions {
@@ -75,6 +76,7 @@ func defaultScanOptions() *scanOptions {
Output: options.DefaultOutput(),
UpdateCheck: options.DefaultUpdateCheck(),
Catalog: options.DefaultCatalog(),
Cache: options.DefaultCache(),
}
}
+131
View File
@@ -0,0 +1,131 @@
package options
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"github.com/adrg/xdg"
"github.com/mitchellh/go-homedir"
"github.com/anchore/clio"
"github.com/anchore/syft/internal/cache"
"github.com/anchore/syft/internal/log"
)
// Cache provides configuration for the Syft caching behavior
type Cache struct {
Dir string `yaml:"dir" mapstructure:"dir"`
TTL string `yaml:"ttl" mapstructure:"ttl"`
}
func (c *Cache) DescribeFields(descriptions clio.FieldDescriptionSet) {
descriptions.Add(&c.Dir, "root directory to cache any downloaded content; empty string will use an in-memory cache")
descriptions.Add(&c.TTL, "time to live for cached data; setting this to 0 will disable caching entirely")
}
func (c *Cache) PostLoad() error {
ttl, err := parseDuration(c.TTL)
if err != nil {
log.Warnf("unable to parse duration '%v', using default (%s) due to: %v", c.TTL, durationToString(defaultTTL()), err)
ttl = defaultTTL()
}
// if TTL is <= 0, disable caching entirely
if ttl <= 0 {
cache.SetManager(nil)
return nil
}
// if dir == "" but we have a TTL, use an in-memory cache
if c.Dir == "" {
cache.SetManager(cache.NewInMemory(ttl))
return nil
}
dir, err := homedir.Expand(c.Dir)
if err != nil {
log.Warnf("unable to expand cache directory %s: %v", c.Dir, err)
cache.SetManager(cache.NewInMemory(ttl))
} else {
m, err := cache.NewFromDir(dir, ttl)
if err != nil {
log.Warnf("unable to get filesystem cache at %s: %v", c.Dir, err)
cache.SetManager(cache.NewInMemory(ttl))
} else {
cache.SetManager(m)
}
}
return nil
}
var _ interface {
clio.PostLoader
clio.FieldDescriber
} = (*Cache)(nil)
func DefaultCache() Cache {
return Cache{
Dir: defaultDir(),
TTL: durationToString(defaultTTL()),
}
}
func defaultTTL() time.Duration {
return 7 * 24 * time.Hour
}
func defaultDir() string {
var err error
cacheRoot := xdg.CacheHome
if cacheRoot == "" {
cacheRoot, err = homedir.Dir()
if err != nil {
cacheRoot = os.TempDir()
log.Debugf("unable to get stable cache directory due to: %v, defaulting cache to temp dir: %s", err, cacheRoot)
} else {
cacheRoot = filepath.Join(cacheRoot, ".cache")
}
}
return filepath.Join(cacheRoot, "syft")
}
func durationToString(duration time.Duration) string {
days := int64(duration / (24 * time.Hour))
remain := duration % (24 * time.Hour)
out := ""
if days > 0 {
out = fmt.Sprintf("%vd", days)
}
if remain != 0 {
out += remain.String()
}
if out == "" {
return "0"
}
return out
}
func parseDuration(duration string) (time.Duration, error) {
whitespace := regexp.MustCompile(`\s+`)
duration = strings.ToLower(whitespace.ReplaceAllString(duration, ""))
parts := strings.SplitN(duration, "d", 2)
var days time.Duration
var remain time.Duration
var err error
if len(parts) > 1 {
numDays, daysErr := strconv.Atoi(parts[0])
if daysErr != nil {
return 0, daysErr
}
days = time.Duration(numDays) * 24 * time.Hour
if len(parts[1]) > 0 {
remain, err = time.ParseDuration(parts[1])
}
} else {
remain, err = time.ParseDuration(duration)
}
return days + remain, err
}
+313
View File
@@ -0,0 +1,313 @@
package options
import (
"io"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/adrg/xdg"
"github.com/mitchellh/go-homedir"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/cache"
)
func Test_defaultDir(t *testing.T) {
tmpDir := filepath.Join(t.TempDir(), "cache-temp")
xdgCacheDir := filepath.Join(tmpDir, "fake-xdg-cache")
homeDir := filepath.Join(tmpDir, "fake-home")
tests := []struct {
name string
env map[string]string
expected string
}{
{
name: "no-xdg",
env: map[string]string{
"HOME": homeDir,
},
expected: homeDir,
},
{
name: "xdg-cache",
env: map[string]string{
"XDG_CACHE_HOME": xdgCacheDir,
},
expected: xdgCacheDir,
},
}
// capture all the initial environment variables to reset them before we reset library caches
env := map[string]string{
"HOME": "",
"XDG_DATA_HOME": "",
"XDG_DATA_DIRS": "",
"XDG_CONFIG_HOME": "",
"XDG_CONFIG_DIRS": "",
"XDG_STATE_HOME": "",
"XDG_CACHE_HOME": "",
"XDG_RUNTIME_DIR": "",
}
for k := range env {
env[k] = os.Getenv(k)
}
unsetEnv := func(t *testing.T) {
for k := range env {
t.Setenv(k, "")
}
}
resetEnv := func() {
for k, v := range env {
if v == "" {
_ = os.Unsetenv(k)
} else {
_ = os.Setenv(k, v)
}
}
homedir.Reset()
xdg.Reload()
}
t.Cleanup(resetEnv)
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
defer resetEnv()
unsetEnv(t)
for k, v := range test.env {
t.Setenv(k, v)
}
homedir.Reset()
xdg.Reload()
got := defaultDir()
require.True(t, strings.HasPrefix(got, test.expected))
})
}
}
func Test_cacheOptions(t *testing.T) {
tmp := t.TempDir()
tests := []struct {
name string
opts Cache
test func(t *testing.T)
}{
{
name: "disable-1",
opts: Cache{
Dir: "some-dir",
TTL: "0",
},
test: func(t *testing.T) {
c := cache.GetManager().GetCache("test-disable-1", "v-disable-1")
err := c.Write("key-disable-1", strings.NewReader("some-value-disable-1"))
require.NoError(t, err)
rdr, err := c.Read("key-disable-1")
require.Nil(t, rdr)
require.Error(t, err)
},
},
{
name: "disable-2",
opts: Cache{
Dir: "some-dir",
TTL: "0s",
},
test: func(t *testing.T) {
c := cache.GetManager().GetCache("test-disable-2", "v-disable-2")
err := c.Write("key-disable-2", strings.NewReader("some-value-disable-2"))
require.NoError(t, err)
rdr, err := c.Read("key-disable-2")
require.Nil(t, rdr)
require.Error(t, err)
},
},
{
name: "disable-3",
opts: Cache{
Dir: "some-dir",
TTL: "0d",
},
test: func(t *testing.T) {
c := cache.GetManager().GetCache("test-disable-3", "v-disable-3")
err := c.Write("key-disable-3", strings.NewReader("some-value-disable-3"))
require.NoError(t, err)
rdr, err := c.Read("key-disable-3")
require.Nil(t, rdr)
require.Error(t, err)
},
},
{
name: "in-memory",
opts: Cache{
Dir: "",
TTL: "10m",
},
test: func(t *testing.T) {
c := cache.GetManager().GetCache("test-mem", "v-mem")
err := c.Write("key-mem", strings.NewReader("some-value-mem"))
require.NoError(t, err)
rdr, err := c.Read("key-mem")
require.NotNil(t, rdr)
defer internal.CloseAndLogError(rdr, "")
require.NoError(t, err)
data, err := io.ReadAll(rdr)
require.NoError(t, err)
require.Equal(t, "some-value-mem", string(data))
require.NoDirExists(t, filepath.Join("test-mem", "v-mem"))
},
},
{
name: "on disk",
opts: Cache{
Dir: tmp,
TTL: "10m",
},
test: func(t *testing.T) {
c := cache.GetManager().GetCache("test-disk", "v-disk")
err := c.Write("key-disk", strings.NewReader("some-value-disk"))
require.NoError(t, err)
rdr, err := c.Read("key-disk")
require.NotNil(t, rdr)
defer internal.CloseAndLogError(rdr, "")
require.NoError(t, err)
data, err := io.ReadAll(rdr)
require.NoError(t, err)
require.Equal(t, "some-value-disk", string(data))
require.DirExists(t, filepath.Join(tmp, "test-disk", "v-disk"))
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
original := cache.GetManager()
defer cache.SetManager(original)
err := test.opts.PostLoad()
require.NoError(t, err)
test.test(t)
})
}
}
func Test_parseDuration(t *testing.T) {
tests := []struct {
duration string
expect time.Duration
err require.ErrorAssertionFunc
}{
{
duration: "0d",
expect: 0,
},
{
duration: "0m",
expect: 0,
},
{
duration: "0s",
expect: 0,
},
{
duration: "0",
expect: 0,
},
{
duration: "1d",
expect: 24 * time.Hour,
},
{
duration: "7d",
expect: 7 * 24 * time.Hour,
},
{
duration: "365D",
expect: 365 * 24 * time.Hour,
},
{
duration: "7d1h1m1s",
expect: 7*24*time.Hour + time.Hour + time.Minute + time.Second,
},
{
duration: "7d 1h 1m 1s",
expect: 7*24*time.Hour + time.Hour + time.Minute + time.Second,
},
{
duration: "2h",
expect: 2 * time.Hour,
},
{
duration: "2h5m",
expect: 2*time.Hour + 5*time.Minute,
},
{
duration: "2h 5m",
expect: 2*time.Hour + 5*time.Minute,
},
{
duration: "d24h",
err: require.Error,
},
}
for _, test := range tests {
t.Run(test.duration, func(t *testing.T) {
got, err := parseDuration(test.duration)
if test.err != nil {
test.err(t, err)
return
} else {
require.NoError(t, err)
}
require.Equal(t, test.expect, got)
})
}
}
func Test_durationToString(t *testing.T) {
tests := []struct {
duration time.Duration
expect string
err require.ErrorAssertionFunc
}{
{
expect: "1d",
duration: 24 * time.Hour,
},
{
expect: "7d",
duration: 7 * 24 * time.Hour,
},
{
expect: "7d1h1m1s",
duration: 7*24*time.Hour + time.Hour + time.Minute + time.Second,
},
{
expect: "2h0m0s",
duration: 2 * time.Hour,
},
{
expect: "2h5m0s",
duration: 2*time.Hour + 5*time.Minute,
},
}
for _, test := range tests {
t.Run(test.expect, func(t *testing.T) {
got := durationToString(test.duration)
require.Equal(t, test.expect, got)
})
}
}
+3
View File
@@ -64,6 +64,7 @@ func DefaultCatalog() Catalog {
Package: defaultPackageConfig(),
LinuxKernel: defaultLinuxKernelConfig(),
Golang: defaultGolangConfig(),
Java: defaultJavaConfig(),
File: defaultFileConfig(),
Relationships: defaultRelationshipsConfig(),
Source: defaultSourceConfig(),
@@ -150,6 +151,8 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config {
GuessUnpinnedRequirements: cfg.Python.GuessUnpinnedRequirements,
},
JavaArchive: java.DefaultArchiveCatalogerConfig().
WithUseMavenLocalRepository(cfg.Java.UseMavenLocalRepository).
WithMavenLocalRepositoryDir(cfg.Java.MavenLocalRepositoryDir).
WithUseNetwork(cfg.Java.UseNetwork).
WithMavenBaseURL(cfg.Java.MavenURL).
WithArchiveTraversal(archiveSearch, cfg.Java.MaxParentRecursiveDepth),
+30 -8
View File
@@ -1,24 +1,46 @@
package options
import "github.com/anchore/clio"
import (
"github.com/anchore/clio"
"github.com/anchore/syft/syft/pkg/cataloger/java"
)
type javaConfig struct {
UseNetwork bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"`
UseMavenLocalRepository bool `yaml:"use-maven-local-repository" json:"use-maven-local-repository" mapstructure:"use-maven-local-repository"`
MavenLocalRepositoryDir string `yaml:"maven-local-repository-dir" json:"maven-local-repository-dir" mapstructure:"maven-local-repository-dir"`
MavenURL string `yaml:"maven-url" json:"maven-url" mapstructure:"maven-url"`
MaxParentRecursiveDepth int `yaml:"max-parent-recursive-depth" json:"max-parent-recursive-depth" mapstructure:"max-parent-recursive-depth"`
}
func defaultJavaConfig() javaConfig {
def := java.DefaultArchiveCatalogerConfig()
return javaConfig{
UseNetwork: def.UseNetwork,
MaxParentRecursiveDepth: def.MaxParentRecursiveDepth,
UseMavenLocalRepository: def.UseMavenLocalRepository,
MavenLocalRepositoryDir: def.MavenLocalRepositoryDir,
MavenURL: def.MavenBaseURL,
}
}
var _ interface {
clio.FieldDescriber
} = (*javaConfig)(nil)
func (o *javaConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
descriptions.Add(&o.UseNetwork, `enables Syft to use the network to fill in more detailed information about artifacts
currently this enables searching maven-url for license data
when running across pom.xml files that could have more information, syft will
explicitly search maven for license information by querying the online pom when this is true
this option is helpful for when the parent pom has more data,
that is not accessible from within the final built artifact`)
descriptions.Add(&o.UseNetwork, `enables Syft to use the network to fetch version and license information for packages when
a parent or imported pom file is not found in the local maven repository.
the pom files are downloaded from the remote Maven repository at 'maven-url'`)
descriptions.Add(&o.MavenURL, `maven repository to use, defaults to Maven central`)
descriptions.Add(&o.MaxParentRecursiveDepth, `depth to recursively resolve parent POMs`)
descriptions.Add(&o.MaxParentRecursiveDepth, `depth to recursively resolve parent POMs, no limit if <= 0`)
descriptions.Add(&o.UseMavenLocalRepository, `use the local Maven repository to retrieve pom files. When Maven is installed and was previously used
for building the software that is being scanned, then most pom files will be available in this
repository on the local file system. this greatly speeds up scans. when all pom files are available
in the local repository, then 'use-network' is not needed.
TIP: If you want to download all required pom files to the local repository without running a full
build, run 'mvn help:effective-pom' before performing the scan with syft.`)
descriptions.Add(&o.MavenLocalRepositoryDir, `override the default location of the local Maven repository.
the default is the subdirectory '.m2/repository' in your home directory`)
}
@@ -35,7 +35,7 @@ var imageOnlyTestCases = []testCase{
pkgType: pkg.PythonPkg,
pkgLanguage: pkg.Python,
pkgInfo: map[string]string{
"Pygments": "2.6.1",
"pygments": "2.6.1",
"requests": "2.22.0",
"somerequests": "3.22.0",
"someotherpkg": "3.19.0",
@@ -172,7 +172,7 @@ var dirOnlyTestCases = []testCase{
"passlib": "1.7.2",
"mypy": "v0.770",
// common to image and directory
"Pygments": "2.6.1",
"pygments": "2.6.1",
"requests": "2.22.0",
"somerequests": "3.22.0",
"someotherpkg": "3.19.0",
@@ -388,6 +388,14 @@ var dirOnlyTestCases = []testCase{
"swift-numerics": "1.0.2",
},
},
{
name: "find swipl pack package manager packages",
pkgType: pkg.SwiplPackPkg,
pkgLanguage: pkg.Swipl,
pkgInfo: map[string]string{
"hdt": "0.5.2",
},
},
{
name: "find github action packages (from usage in workflow files and composite actions)",
pkgType: pkg.GithubActionPkg,
@@ -51,6 +51,7 @@ func TestPkgCoverageImage(t *testing.T) {
definedLanguages.Remove(pkg.Rust.String())
definedLanguages.Remove(pkg.Dart.String())
definedLanguages.Remove(pkg.Swift.String())
definedLanguages.Remove(pkg.Swipl.String())
definedLanguages.Remove(pkg.CPP.String())
definedLanguages.Remove(pkg.Haskell.String())
definedLanguages.Remove(pkg.Elixir.String())
@@ -76,6 +77,7 @@ func TestPkgCoverageImage(t *testing.T) {
definedPkgs.Remove(string(pkg.LinuxKernelPkg))
definedPkgs.Remove(string(pkg.LinuxKernelModulePkg))
definedPkgs.Remove(string(pkg.SwiftPkg))
definedPkgs.Remove(string(pkg.SwiplPackPkg))
definedPkgs.Remove(string(pkg.GithubActionPkg))
definedPkgs.Remove(string(pkg.GithubActionWorkflowPkg))
@@ -10,7 +10,8 @@ import (
func TestMarinerDistroless(t *testing.T) {
sbom, _ := catalogFixtureImage(t, "image-mariner-distroless", source.SquashedScope)
expectedPkgs := 12
// 12 RPMs + 2 binaries with ELF package notes claiming to be RPMs
expectedPkgs := 14
actualPkgs := 0
for range sbom.Artifacts.Packages.Enumerate(pkg.RpmPkg) {
actualPkgs += 1
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/anchore/syft/internal/relationship"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/source"
)
@@ -44,12 +45,13 @@ func TestBinaryElfRelationships(t *testing.T) {
}
}
relationshipIndex := relationship.NewIndex(sbom.Relationships...)
for name, expectedDepNames := range expectedGraph {
pkgId := nameToId[name]
p := sbom.Artifacts.Packages.Package(pkgId)
require.NotNil(t, p, "expected package %q to be present in the SBOM", name)
rels := sbom.RelationshipsForPackage(*p, artifact.DependencyOfRelationship)
rels := relationshipIndex.References(*p, artifact.DependencyOfRelationship)
require.NotEmpty(t, rels, "expected package %q to have relationships", name)
toIds := map[artifact.ID]struct{}{}
@@ -0,0 +1,10 @@
name(hdt).
version('0.5.2').
% TODO: swipl_version([90121]).
title('Access RDF HDT files').
keywords(['RDF']).
author( 'Jan Wielemaker', 'J.Wielemaker@vu.nl' ).
packager( 'Jan Wielemaker', 'J.Wielemaker@vu.nl' ).
maintainer( 'Jan Wielemaker', 'J.Wielemaker@vu.nl' ).
home( 'https://github.com/JanWielemaker/hdt' ).
download( 'https://github.com/JanWielemaker/hdt/archive/V*.zip' ).
+34 -31
View File
@@ -17,29 +17,29 @@ require (
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/packageurl-go v0.1.1-0.20240507183024-848e011fc24f
github.com/anchore/stereoscope v0.0.3-0.20240501181043-2e9894674185
github.com/anchore/stereoscope v0.0.3-0.20240725180315-50ce3be7aa1f
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
// we are hinting brotli to latest due to warning when installing archiver v3:
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
github.com/bmatcuk/doublestar/v4 v4.6.1
github.com/charmbracelet/bubbles v0.18.0
github.com/charmbracelet/bubbletea v0.26.4
github.com/charmbracelet/lipgloss v0.11.0
github.com/charmbracelet/bubbletea v0.26.6
github.com/charmbracelet/lipgloss v0.12.1
github.com/dave/jennifer v1.7.0
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
github.com/distribution/reference v0.6.0
github.com/docker/docker v26.1.4+incompatible
github.com/docker/docker v27.1.1+incompatible
github.com/dustin/go-humanize v1.0.1
github.com/elliotchance/phpserialize v1.4.0
github.com/facebookincubator/nvdtools v0.1.5
github.com/github/go-spdx/v2 v2.2.0
github.com/gkampitakis/go-snaps v0.5.4
github.com/github/go-spdx/v2 v2.3.1
github.com/gkampitakis/go-snaps v0.5.7
github.com/go-git/go-billy/v5 v5.5.0
github.com/go-git/go-git/v5 v5.12.0
github.com/go-test/deep v1.1.0
github.com/go-test/deep v1.1.1
github.com/google/go-cmp v0.6.0
github.com/google/go-containerregistry v0.19.1
github.com/google/go-containerregistry v0.20.1
github.com/google/licensecheck v0.3.1
github.com/google/uuid v1.6.0
github.com/gookit/color v1.5.4
@@ -55,38 +55,43 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/mitchellh/mapstructure v1.5.0
github.com/moby/sys/mountinfo v0.7.1
github.com/moby/sys/mountinfo v0.7.2
github.com/olekukonko/tablewriter v0.0.5
github.com/opencontainers/go-digest v1.0.0
github.com/pelletier/go-toml v1.9.5
github.com/quasilyte/go-ruleguard/dsl v0.3.22
github.com/saferwall/pe v1.5.3
github.com/saferwall/pe v1.5.4
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
github.com/sanity-io/litter v1.5.5
github.com/sassoftware/go-rpmutils v0.4.0
// 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.3.2-0.20230802210424-5b0b94c5c0d3
github.com/spdx/tools-golang v0.5.4
github.com/spdx/tools-golang v0.5.5
github.com/spf13/afero v1.11.0
github.com/spf13/cobra v1.8.0
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
github.com/vbatts/go-mtree v0.5.3
github.com/vbatts/go-mtree v0.5.4
github.com/vifraa/gopom v1.0.0
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651
github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0
github.com/xeipuuv/gojsonschema v1.2.0
github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1
go.uber.org/goleak v1.3.0
golang.org/x/mod v0.18.0
golang.org/x/net v0.26.0
golang.org/x/mod v0.20.0
golang.org/x/net v0.27.0
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.30.0
modernc.org/sqlite v1.31.1
)
require google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
require github.com/magiconair/properties v1.8.7
require (
github.com/BurntSushi/toml v1.4.0
github.com/adrg/xdg v0.5.0
github.com/magiconair/properties v1.8.7
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678
)
require (
dario.cat/mergo v1.0.0 // indirect
@@ -98,7 +103,6 @@ require (
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/adrg/xdg v0.4.0 // indirect
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
@@ -106,7 +110,7 @@ require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/charmbracelet/harmonica v0.2.0 // indirect
github.com/charmbracelet/x/ansi v0.1.2 // indirect
github.com/charmbracelet/x/ansi v0.1.4 // indirect
github.com/charmbracelet/x/input v0.1.0 // indirect
github.com/charmbracelet/x/term v0.1.1 // indirect
github.com/charmbracelet/x/windows v0.1.0 // indirect
@@ -121,7 +125,7 @@ require (
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/cli v24.0.0+incompatible // indirect
github.com/docker/cli v27.0.3+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.4.0 // indirect
@@ -134,7 +138,7 @@ require (
github.com/felixge/fgprof v0.9.3 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.4 // indirect
github.com/gkampitakis/ciinfo v0.3.0 // indirect
github.com/gkampitakis/go-diff v1.3.2 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
@@ -159,7 +163,7 @@ require (
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/maruel/natural v1.1.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
@@ -179,13 +183,13 @@ require (
github.com/muesli/termenv v0.15.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc3 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/opencontainers/runc v1.1.12 // indirect
github.com/opencontainers/runtime-spec v1.1.0-rc.1 // indirect
github.com/opencontainers/selinux v1.11.0 // indirect
github.com/pborman/indent v1.2.1 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pierrec/lz4/v4 v4.1.19 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/profile v1.7.0 // indirect
@@ -205,8 +209,8 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/sylabs/sif/v2 v2.11.5 // indirect
github.com/sylabs/squashfs v0.6.1 // indirect
github.com/sylabs/sif/v2 v2.17.1 // indirect
github.com/sylabs/squashfs v1.0.0 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/tidwall/gjson v1.17.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
@@ -226,11 +230,10 @@ require (
go.opentelemetry.io/otel/trace v1.19.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/term v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
@@ -240,7 +243,7 @@ require (
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.50.9 // indirect
modernc.org/libc v1.55.3 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/strutil v1.2.0 // indirect
+65 -63
View File
@@ -57,6 +57,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg6
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CycloneDX/cyclonedx-go v0.9.0 h1:inaif7qD8bivyxp7XLgxUYtOXWtDez7+j72qKTMQTb8=
github.com/CycloneDX/cyclonedx-go v0.9.0/go.mod h1:NE/EWvzELOFlG6+ljX/QeMlVt9VKcTwu8u0ccsACEsw=
@@ -83,8 +85,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY=
github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -111,8 +113,8 @@ github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZV
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
github.com/anchore/packageurl-go v0.1.1-0.20240507183024-848e011fc24f h1:B/E9ixKNCasntpoch61NDaQyGPDXLEJlL+B9B/PbdbA=
github.com/anchore/packageurl-go v0.1.1-0.20240507183024-848e011fc24f/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
github.com/anchore/stereoscope v0.0.3-0.20240501181043-2e9894674185 h1:SuViDJ27nZ+joGdKbAkxAlm7tYMt9NTxTZZ05po4hls=
github.com/anchore/stereoscope v0.0.3-0.20240501181043-2e9894674185/go.mod h1:ckIamHiRMp8iBwWoTtE5Xkt9VQ5QC+6+O4VzwqyZr5Q=
github.com/anchore/stereoscope v0.0.3-0.20240725180315-50ce3be7aa1f h1:xuBvotcht1Ns8IdaC4UuYV1U8MFln9c5ELeo5bzDEO8=
github.com/anchore/stereoscope v0.0.3-0.20240725180315-50ce3be7aa1f/go.mod h1:DcQdMes8SwpFli3rDH0v+Vd9qU9Jariq7JSHNJV5X/A=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
@@ -155,14 +157,14 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
github.com/charmbracelet/bubbletea v0.26.4 h1:2gDkkzLZaTjMl/dQBpNVtnvcCxsh/FCkimep7FC9c40=
github.com/charmbracelet/bubbletea v0.26.4/go.mod h1:P+r+RRA5qtI1DOHNFn0otoNwB4rn+zNAzSj/EXz6xU0=
github.com/charmbracelet/bubbletea v0.26.6 h1:zTCWSuST+3yZYZnVSvbXwKOPRSNZceVeqpzOLN2zq1s=
github.com/charmbracelet/bubbletea v0.26.6/go.mod h1:dz8CWPlfCCGLFbBlTY4N7bjLiyOGDJEnd2Muu7pOWhk=
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g=
github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8=
github.com/charmbracelet/x/ansi v0.1.2 h1:6+LR39uG8DE6zAmbu023YlqjJHkYXDF1z36ZwzO4xZY=
github.com/charmbracelet/x/ansi v0.1.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs=
github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8=
github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ=
github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28=
github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
@@ -209,7 +211,7 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
@@ -225,12 +227,12 @@ github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4i
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v24.0.0+incompatible h1:0+1VshNwBQzQAx9lOl+OYCTCEAD8fKs/qeXMx3O0wqM=
github.com/docker/cli v24.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v27.0.3+incompatible h1:usGs0/BoBW8MWxGeEtqPMkzOY56jZ6kYlSN5BLDioCQ=
github.com/docker/cli v27.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU=
github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
@@ -282,17 +284,17 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0FnbhiOsEro=
github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/github/go-spdx/v2 v2.2.0 h1:yBBLMasHA70Ujd35OpL/OjJOWWVNXcJGbars0GinGRI=
github.com/github/go-spdx/v2 v2.2.0/go.mod h1:hMCrsFgT0QnCwn7G8gxy/MxMpy67WgZrwFeISTn0o6w=
github.com/github/go-spdx/v2 v2.3.1 h1:ffGuHTbHuHzWPt53n8f9o8clGutuLPObo3zB4JAjxU8=
github.com/github/go-spdx/v2 v2.3.1/go.mod h1:2ZxKsOhvBp+OYBDlsGnUMcchLeo2mrpEBn2L1C+U3IQ=
github.com/gkampitakis/ciinfo v0.3.0 h1:gWZlOC2+RYYttL0hBqcoQhM7h1qNkVqvRCV1fOvpAv8=
github.com/gkampitakis/ciinfo v0.3.0/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
github.com/gkampitakis/go-snaps v0.5.4 h1:GX+dkKmVsRenz7SoTbdIEL4KQARZctkMiZ8ZKprRwT8=
github.com/gkampitakis/go-snaps v0.5.4/go.mod h1:ZABkO14uCuVxBHAXAfKG+bqNz+aa1bGPAg8jkI0Nk8Y=
github.com/gkampitakis/go-snaps v0.5.7 h1:uVGjHR4t4pPHU944udMx7VKHpwepZXmvDMF+yDmI0rg=
github.com/gkampitakis/go-snaps v0.5.7/go.mod h1:ZABkO14uCuVxBHAXAfKG+bqNz+aa1bGPAg8jkI0Nk8Y=
github.com/glebarez/go-sqlite v1.20.3 h1:89BkqGOXR9oRmG58ZrzgoY/Fhy5x0M+/WV48U5zVrZ4=
github.com/glebarez/go-sqlite v1.20.3/go.mod h1:u3N6D/wftiAzIOJtZl6BmedqxmmkDfH3q+ihjqxC9u0=
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
@@ -321,8 +323,8 @@ github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSr
github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -382,8 +384,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY=
github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
github.com/google/go-containerregistry v0.20.1 h1:eTgx9QNYugV4DN5mz4U8hiAGTi1ybXn0TPi4Smd8du0=
github.com/google/go-containerregistry v0.20.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs=
github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY=
@@ -520,8 +522,9 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
@@ -581,8 +584,8 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
@@ -615,8 +618,8 @@ github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8=
github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
github.com/opencontainers/runtime-spec v1.1.0-rc.1 h1:wHa9jroFfKGQqFHj0I1fMRKLl0pfj+ynAqBxo3v6u9w=
@@ -633,8 +636,8 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.19 h1:tYLzDnjDXh9qIxSTKHwXwOYmm9d887Y7Y1ZkyXYHAN4=
github.com/pierrec/lz4/v4 v4.1.19/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -682,8 +685,8 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/saferwall/pe v1.5.3 h1:tZ2KJWeJK6N2jjJx+B9hm+wq6qe0o56pql2PXUaQ9eI=
github.com/saferwall/pe v1.5.3/go.mod h1:mJx+PuptmNpoPFBNhWs/uDMFL/kTHVZIkg0d4OUJFbQ=
github.com/saferwall/pe v1.5.4 h1:tLmMggEMUfeqrpJ25zS/okUQmyFdD5xWKL2+z9njCqg=
github.com/saferwall/pe v1.5.4/go.mod h1:mJx+PuptmNpoPFBNhWs/uDMFL/kTHVZIkg0d4OUJFbQ=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
@@ -724,8 +727,8 @@ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9yS
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
github.com/spdx/tools-golang v0.5.4 h1:fRW4iz16P1ZCUtWStFqS6YiMgnK7WgfTFU/lrsYlvqY=
github.com/spdx/tools-golang v0.5.4/go.mod h1:MVIsXx8ZZzaRWNQpUDhC4Dud34edUYJYecciXgrw5vE=
github.com/spdx/tools-golang v0.5.5 h1:61c0KLfAcNqAjlg6UNMdkwpMernhw3zVRwDZ2x9XOmk=
github.com/spdx/tools-golang v0.5.5/go.mod h1:MVIsXx8ZZzaRWNQpUDhC4Dud34edUYJYecciXgrw5vE=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
@@ -735,8 +738,8 @@ github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -766,10 +769,10 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/sylabs/sif/v2 v2.11.5 h1:7ssPH3epSonsTrzbS1YxeJ9KuqAN7ISlSM61a7j/mQM=
github.com/sylabs/sif/v2 v2.11.5/go.mod h1:GBoZs9LU3e4yJH1dcZ3Akf/jsqYgy5SeguJQC+zd75Y=
github.com/sylabs/squashfs v0.6.1 h1:4hgvHnD9JGlYWwT0bPYNt9zaz23mAV3Js+VEgQoRGYQ=
github.com/sylabs/squashfs v0.6.1/go.mod h1:ZwpbPCj0ocIvMy2br6KZmix6Gzh6fsGQcCnydMF+Kx8=
github.com/sylabs/sif/v2 v2.17.1 h1:p6Sl0LWyShXBj2SBsS1dMOMIMrZHe8pwBnBrYt6uo4M=
github.com/sylabs/sif/v2 v2.17.1/go.mod h1:XUGB6AQUXGkms3qPOPdevctT3lBLRLWZNWHVnt5HMKE=
github.com/sylabs/squashfs v1.0.0 h1:xAyMS21ogglkuR5HaY55PCfqY3H32ma9GkasTYo28Zg=
github.com/sylabs/squashfs v1.0.0/go.mod h1:rhWzvgefq1X+R+LZdts10hfMsTg3g74OfGunW8tvg/4=
github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo=
github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
@@ -791,8 +794,8 @@ github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vbatts/go-mtree v0.5.3 h1:S/jYlfG8rZ+a0bhZd+RANXejy7M4Js8fq9U+XoWTd5w=
github.com/vbatts/go-mtree v0.5.3/go.mod h1:eXsdoPMdL2jcJx6HweWi9lYQxBsTp4lNhqqAjgkZUg8=
github.com/vbatts/go-mtree v0.5.4 h1:OMAb8jaCyiFA7zXj0Zc/oARcxBDBoeu2LizjB8BVJl0=
github.com/vbatts/go-mtree v0.5.4/go.mod h1:5GqJbVhm9BBiCc4K5uc/c42FPgXulHaQs4sFUEfIWMo=
github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck=
github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY=
github.com/vifraa/gopom v1.0.0 h1:L9XlKbyvid8PAIK8nr0lihMApJQg/12OBvMA28BcWh0=
@@ -875,8 +878,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -917,8 +920,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -959,15 +962,14 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1079,15 +1081,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1357,18 +1359,18 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk=
modernc.org/cc/v4 v4.21.2/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.17.8 h1:yyWBf2ipA0Y9GGz/MmCmi3EFpKgeS7ICrAFes+suEbs=
modernc.org/ccgo/v4 v4.17.8/go.mod h1:buJnJ6Fn0tyAdP/dqePbrrvLyr6qslFfTbFrCuaYvtA=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.50.9 h1:hIWf1uz55lorXQhfoEoezdUHjxzuO6ceshET/yWjSjk=
modernc.org/libc v1.50.9/go.mod h1:15P6ublJ9FJR8YQCGy8DeQ2Uwur7iW9Hserr/T3OFZE=
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
@@ -1377,8 +1379,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.30.0 h1:8YhPUs/HTnlEgErn/jSYQTwHN/ex8CjHHjg+K9iG7LM=
modernc.org/sqlite v1.30.0/go.mod h1:cgkTARJ9ugeXSNaLBPK3CqbOe7Ec7ZhWPoMFGldEYEw=
modernc.org/sqlite v1.31.1 h1:XVU0VyzxrYHlBhIs1DiEgSl0ZtdnPtbLVy8hSkzxGrs=
modernc.org/sqlite v1.31.1/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
+51
View File
@@ -0,0 +1,51 @@
# Caching
All caches are created from a global `manager`. By defaut this is a `bypassedCache`, which performs no caching.
One benefit of this is that tests don't need to worry about caching causing issues unless they explicitly need
to test the cache and can opt-in using the `cache.TestCache(t)` helper.
Syft sets a `filesystemCache` when the [cache options](../../cmd/syft/internal/options/cache.go) are loaded.
When using the `filesystemCache` all items are stored on disk under a root directory, generally in the form of:
```
<rootDir>/<named-cache>/<data-version>/path/to/data
```
# Using the cache
The easiest and preferred method to use the cache is a `cache.Resolver`, which automatically creates a `<data-version>`
based on the _structure_ of the provided type.
If the structure changes in any way it will end up with a new version key and all will re populate this new key,
ignoring cached values from older, different versions.
The resolver will store items using the `json` package to serialize/deserialize values, so to save space
it is encouraged to use `omitempty`. For example:
```go
type myCacheItem struct {
Name string `json:"name",omitempty`
}
```
It is possible to use core types such as `pkg.Package` as long as they support the standard `json` serialization,
but this is discouraged in order to decouple changes to them from affecting the information stored in the cache.
To get a cache for this type:
```go
resolver := cache.GetResolver[myCacheItem]("myCacheName", "v1")
```
Using the `resolver` is a single call, which manages checking for items in the cache, expiry times,
and if not found invoking the callback to populate the cache and return a value:
```go
data := resolver.Resolve("some/cache/key", func() (myCacheItem, error) {
// do things to return a myCacheItem or error
})
```
If it is common that checking for an item will result in errors, and you do not want to re-run the resolve function
when errors are encountered, instead of using `GetResolver`, you can use `GetResolverCachingErrors`, which is useful
for things such as resolving artifacts over a network, where a number of them will not be resolved, and you do not want
to continue to have the expense of running the network resolution. This should be used when it is acceptable a network
outage and cached errors is an acceptable risk.
An example can be seen in the [golang cataloger](../../syft/pkg/cataloger/golang/licenses.go) fetching remote licenses.
+24
View File
@@ -0,0 +1,24 @@
package cache
import "io"
type bypassedCache struct{}
func (b *bypassedCache) Read(_ string) (ReaderAtCloser, error) {
return nil, errNotFound
}
func (b *bypassedCache) Write(_ string, contents io.Reader) error {
if closer, ok := contents.(io.Closer); ok {
_ = closer.Close()
}
return nil
}
func (b *bypassedCache) GetCache(_, _ string) Cache {
return b
}
func (b *bypassedCache) RootDirs() []string {
return nil
}
+18
View File
@@ -0,0 +1,18 @@
package cache
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func Test_bypassedCache(t *testing.T) {
m := bypassedCache{}
cache := m.GetCache("name", "version")
err := cache.Write("test", strings.NewReader("value"))
require.NoError(t, err)
rdr, err := cache.Read("test")
require.Nil(t, rdr)
require.ErrorIs(t, err, errNotFound)
}
+49
View File
@@ -0,0 +1,49 @@
package cache
import (
"io"
)
// Manager is responsible for managing cache data and instantiating all caches
type Manager interface {
// GetCache returns a cache scoped to the given named, versioned data
GetCache(name, version string) Cache
// RootDirs returns any root directories this cache manager uses
RootDirs() []string
}
// ReaderAtCloser is an amalgamation of: io.Reader, io.ReaderAt, and io.Closer
type ReaderAtCloser interface {
io.Reader
io.ReaderAt
io.Closer
}
// Cache is what the application interacts with to get and set cached data
type Cache interface {
// Read returns a reader for the cache value, if found and not expired
// or errors when unable to find / expired
Read(key string) (ReaderAtCloser, error)
// Write writes the contents of the reader to the cache
// and closes it, if the reader implements io.Closer
Write(key string, contents io.Reader) error
}
// GetManager returns the global cache manager, which is used to instantiate all caches
func GetManager() Manager {
return manager
}
// SetManager sets the global cache manager, which is used to instantiate all caches.
// Setting this to nil disables caching.
func SetManager(m Manager) {
if m == nil {
manager = &bypassedCache{}
} else {
manager = m
}
}
var manager Manager = &bypassedCache{}
+32
View File
@@ -0,0 +1,32 @@
package cache
import (
"testing"
"time"
"github.com/stretchr/testify/require"
)
func Test_SetManager(t *testing.T) {
original := GetManager()
defer SetManager(original)
SetManager(nil)
require.NotNil(t, GetManager())
require.IsType(t, &bypassedCache{}, GetManager())
SetManager(NewInMemory(0))
require.NotNil(t, GetManager())
require.IsType(t, &bypassedCache{}, GetManager())
SetManager(NewInMemory(1 * time.Hour))
require.NotNil(t, GetManager())
require.IsType(t, &filesystemCache{}, GetManager())
SetManager(nil)
require.NotNil(t, GetManager())
require.IsType(t, &bypassedCache{}, GetManager())
}
+40
View File
@@ -0,0 +1,40 @@
package cache
import "fmt"
// GetResolverCachingErrors returns a Resolver that caches errors and will return them
// instead of continuing to call the provided resolve functions
func GetResolverCachingErrors[T any](name, version string) Resolver[T] {
return &errorResolver[T]{
resolver: GetResolver[errResponse[T]](name, version),
}
}
type errResponse[T any] struct {
Error string `json:"err,omitempty"`
Value T `json:"val,omitempty"`
}
type errorResolver[T any] struct {
resolver Resolver[errResponse[T]]
}
func (r *errorResolver[T]) Resolve(key string, resolver resolverFunc[T]) (T, error) {
v, err := r.resolver.Resolve(key, func() (errResponse[T], error) {
v, err := resolver()
out := errResponse[T]{
Value: v,
}
if err != nil {
out.Error = err.Error()
}
return out, nil
})
if err != nil {
return v.Value, err
}
if v.Error != "" {
return v.Value, fmt.Errorf(v.Error)
}
return v.Value, nil
}
+47
View File
@@ -0,0 +1,47 @@
package cache
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func Test_errorResolver(t *testing.T) {
original := GetManager()
defer SetManager(original)
SetManager(NewInMemory(time.Hour))
resolver := GetResolverCachingErrors[string]("theCache", "theVersion")
resolveCount := 0
resolveFunc := func() (string, error) {
resolveCount++
return "theValue", nil
}
val, err := resolver.Resolve("theKey", resolveFunc)
require.NoError(t, err)
require.Equal(t, 1, resolveCount)
require.Equal(t, "theValue", val)
val, err = resolver.Resolve("theKey", resolveFunc)
require.NoError(t, err)
require.Equal(t, 1, resolveCount)
require.Equal(t, "theValue", val)
errorCount := 0
errorFunc := func() (string, error) {
errorCount++
return "", fmt.Errorf("an error")
}
_, err = resolver.Resolve("errorValue", errorFunc)
require.ErrorContains(t, err, "an error")
require.Equal(t, 1, errorCount)
_, err = resolver.Resolve("errorValue", errorFunc)
require.ErrorContains(t, err, "an error")
require.Equal(t, 1, errorCount)
}
+120
View File
@@ -0,0 +1,120 @@
package cache
import (
"errors"
"fmt"
"io"
"net/url"
"os"
"path/filepath"
"regexp"
"strings"
"time"
"github.com/spf13/afero"
"github.com/anchore/syft/internal/log"
)
// NewFromDir creates a new cache manager which returns caches stored on disk, rooted at the given directory
func NewFromDir(dir string, ttl time.Duration) (Manager, error) {
dir = filepath.Clean(dir)
fsys, err := subFs(afero.NewOsFs(), dir)
if err != nil {
return nil, err
}
return &filesystemCache{
dir: dir,
fs: fsys,
ttl: ttl,
}, nil
}
const filePermissions = 0700
const dirPermissions = os.ModeDir | filePermissions
type filesystemCache struct {
dir string
fs afero.Fs
ttl time.Duration
}
func (d *filesystemCache) GetCache(name, version string) Cache {
fsys, err := subFs(d.fs, name, version)
if err != nil {
log.Warnf("error getting cache for: %s/%s: %v", name, version, err)
return &bypassedCache{}
}
return &filesystemCache{
dir: filepath.Join(d.dir, name, version),
fs: fsys,
ttl: d.ttl,
}
}
func (d *filesystemCache) RootDirs() []string {
if d.dir == "" {
return nil
}
return []string{d.dir}
}
func (d *filesystemCache) Read(key string) (ReaderAtCloser, error) {
path := makeDiskKey(key)
f, err := d.fs.Open(path)
if err != nil {
log.Tracef("no cache entry for %s %s: %v", d.dir, key, err)
return nil, errNotFound
} else if stat, err := f.Stat(); err != nil || stat == nil || time.Since(stat.ModTime()) > d.ttl {
log.Tracef("cache entry is too old for %s %s", d.dir, key)
return nil, errExpired
}
log.Tracef("using cache for %s %s", d.dir, key)
return f, nil
}
func (d *filesystemCache) Write(key string, contents io.Reader) error {
path := makeDiskKey(key)
return afero.WriteReader(d.fs, path, contents)
}
// subFs returns a writable directory with the given name under the root cache directory returned from findRoot,
// the directory will be created if it does not exist
func subFs(fsys afero.Fs, subDirs ...string) (afero.Fs, error) {
dir := filepath.Join(subDirs...)
dir = filepath.Clean(dir)
stat, err := fsys.Stat(dir)
if errors.Is(err, afero.ErrFileNotFound) {
err = fsys.MkdirAll(dir, dirPermissions)
if err != nil {
return nil, fmt.Errorf("unable to create directory at '%s': %v", dir, err)
}
stat, err = fsys.Stat(dir)
if err != nil {
return nil, err
}
}
if err != nil || stat == nil || !stat.IsDir() {
return nil, fmt.Errorf("unable to verify directory '%s': %v", dir, err)
}
fsys = afero.NewBasePathFs(fsys, dir)
return fsys, err
}
var keyReplacer = regexp.MustCompile("[^-._/a-zA-Z0-9]")
// makeDiskKey makes a safe sub-path but not escape forward slashes, this allows for logical partitioning on disk
func makeDiskKey(key string) string {
// encode single dot directory
if key == "." {
return "%2E"
}
// replace any disallowed chars with encoded form
key = keyReplacer.ReplaceAllStringFunc(key, url.QueryEscape)
// allow . in names but not ..
key = strings.ReplaceAll(key, "..", "%2E%2E")
return key
}
var errNotFound = fmt.Errorf("not found")
var errExpired = fmt.Errorf("expired")
+106
View File
@@ -0,0 +1,106 @@
package cache
import (
"fmt"
"io"
"net/url"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/internal"
)
func Test_filesystemCache(t *testing.T) {
dir := t.TempDir()
man, err := NewFromDir(dir, 1*time.Minute)
require.NoError(t, err)
cacheName := "test"
cacheVersion := "v1"
cache := man.GetCache(cacheName, cacheVersion)
cacheKey := "test-key"
contentsValue := "some contents to cache"
err = cache.Write(cacheKey, strings.NewReader(contentsValue))
require.NoError(t, err)
rdr, err := cache.Read(cacheKey)
require.NoError(t, err)
defer internal.CloseAndLogError(rdr, cacheKey)
contents, err := io.ReadAll(rdr)
require.NoError(t, err)
require.Equal(t, contentsValue, string(contents))
// check the contents were actually written to disk as expected
contents, err = os.ReadFile(filepath.Join(dir, cacheName, cacheVersion, cacheKey))
require.NoError(t, err)
require.Equal(t, contentsValue, string(contents))
_, err = cache.Read("otherKey")
require.ErrorIs(t, err, errNotFound)
}
func Test_makeDiskKey(t *testing.T) {
tests := []struct {
in string
expected string
}{
{
in: "",
expected: "",
},
{
in: ".",
expected: "%2E",
},
{
in: "..",
expected: "%2E%2E",
},
{
in: "github.com",
expected: "github.com",
},
{
in: "../github.com",
expected: "%2E%2E/github.com",
},
{
in: "github.com/../..",
expected: "github.com/%2E%2E/%2E%2E",
},
{
in: "github.com/%2E../..",
expected: "github.com/%252E%2E%2E/%2E%2E",
},
}
for _, test := range tests {
t.Run(test.in, func(t *testing.T) {
got := makeDiskKey(test.in)
// validate appropriate escaping
require.Equal(t, test.expected, got)
// also validate that unescaped string matches original
unescaped, err := url.QueryUnescape(got)
require.NoError(t, err)
require.Equal(t, test.in, unescaped)
})
}
}
func Test_errors(t *testing.T) {
tmp := t.TempDir()
cache := filepath.Join(tmp, "cache")
// make a non-writable directory
require.NoError(t, os.MkdirAll(cache, 0500|os.ModeDir))
// attempt to make cache in non-writable directory
dir := filepath.Join(cache, "dir")
_, err := NewFromDir(dir, time.Hour)
require.ErrorContains(t, err, fmt.Sprintf("unable to create directory at '%s':", dir))
}
+71
View File
@@ -0,0 +1,71 @@
package cache
import (
"fmt"
"reflect"
"github.com/mitchellh/hashstructure/v2"
)
// hashType returns a stable hash based on the structure of the type
func hashType[T any]() string {
// get the base type and hash an empty instance
var t T
empty := emptyValue(reflect.TypeOf(t)).Interface()
hash, err := hashstructure.Hash(empty, hashstructure.FormatV2, &hashstructure.HashOptions{
ZeroNil: false,
IgnoreZeroValue: false,
SlicesAsSets: false,
UseStringer: false,
})
if err != nil {
panic(fmt.Errorf("unable to use type as cache key: %w", err))
}
return fmt.Sprintf("%x", hash)
}
func emptyValue(t reflect.Type) reflect.Value {
switch t.Kind() {
case reflect.Pointer:
e := t.Elem()
v := emptyValue(e)
if v.CanAddr() {
return v.Addr()
}
ptrv := reflect.New(e)
ptrv.Elem().Set(v)
return ptrv
case reflect.Slice:
v := emptyValue(t.Elem())
s := reflect.MakeSlice(t, 1, 1)
s.Index(0).Set(v)
return s
case reflect.Struct:
v := reflect.New(t).Elem()
// get all empty field values, too
for i := 0; i < v.NumField(); i++ {
f := t.Field(i)
if isIgnored(f) {
continue
}
fv := v.Field(i)
if fv.CanSet() {
fv.Set(emptyValue(f.Type))
}
}
return v
default:
return reflect.New(t).Elem()
}
}
func isIgnored(f reflect.StructField) bool {
if !f.IsExported() {
return true
}
tag := f.Tag.Get("hash")
if tag == "-" || tag == "ignore" {
return true
}
return false
}
+123
View File
@@ -0,0 +1,123 @@
package cache
import (
"fmt"
"testing"
"github.com/mitchellh/hashstructure/v2"
"github.com/stretchr/testify/require"
)
func Test_hashType(t *testing.T) {
type t1 struct {
Name string
}
type t2 struct {
Name string
}
type generic[T any] struct {
Val T
}
tests := []struct {
name string
hash func() string
expected string
}{
{
name: "struct 1",
hash: func() string { return hashType[t1]() },
expected: "d106c3ffbf98a0b1",
},
{
name: "slice of struct 1",
hash: func() string { return hashType[[]t1]() },
expected: "8122ace4ee1af0b4",
},
{
name: "slice of struct 2",
hash: func() string { return hashType[[]t2]() },
expected: "8cc04b5808be5bf9",
},
{
name: "ptr 1",
hash: func() string { return hashType[*t1]() },
expected: "d106c3ffbf98a0b1", // same hash as t1, which is ok since the structs are the same
},
{
name: "slice of ptr 1",
hash: func() string { return hashType[[]*t1]() },
expected: "8122ace4ee1af0b4", // same hash as []t1, again underlying serialization is the same
},
{
name: "slice of ptr 2",
hash: func() string { return hashType[[]*t2]() },
expected: "8cc04b5808be5bf9", // same hash as []t2, underlying serialization is the same
},
{
name: "slice of ptr of slice of ptr",
hash: func() string { return hashType[[]*[]*t1]() },
expected: "500d9f5b3a5977ce",
},
{
name: "generic 1",
hash: func() string { return hashType[generic[t1]]() },
expected: "b5fbb30e24400e81",
},
{
name: "generic 2",
hash: func() string { return hashType[generic[t2]]() },
expected: "becdb767c6b22bfa",
},
{
name: "generic with ptr 1",
hash: func() string { return hashType[generic[*t1]]() },
expected: "30c8855bf290fd83",
},
{
name: "generic with ptr 2",
hash: func() string { return hashType[generic[*t2]]() },
expected: "b66366b6ce9e6361",
},
{
name: "generic with slice 1",
hash: func() string { return hashType[generic[[]t1]]() },
expected: "d2ed158942fa6c29",
},
{
name: "generic with slice 2",
hash: func() string { return hashType[generic[[]t2]]() },
expected: "7a7bec575871c179",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require.Equal(t, test.expected, test.hash())
})
}
}
func Test_hashIgnores(t *testing.T) {
hash := func(v any) string {
v, err := hashstructure.Hash(v, hashstructure.FormatV2, &hashstructure.HashOptions{})
require.NoError(t, err)
return fmt.Sprintf("%x", v)
}
type t1 struct {
Name string
notExported string
}
require.Equal(t, hash(t1{notExported: "a value"}), hashType[t1]())
type t2 struct {
Name string
Exported string `hash:"ignore"`
}
require.Equal(t, hash(t2{Exported: "another value"}), hashType[t2]())
type t3 struct {
Name string
Exported string `hash:"-"`
}
require.Equal(t, hash(t3{Exported: "still valued"}), hashType[t3]())
}
+19
View File
@@ -0,0 +1,19 @@
package cache
import (
"time"
"github.com/spf13/afero"
)
// NewInMemory returns an in-memory only cache manager
func NewInMemory(ttl time.Duration) Manager {
if ttl <= 0 {
return &bypassedCache{}
}
return &filesystemCache{
dir: "",
fs: afero.NewMemMapFs(),
ttl: ttl,
}
}
+37
View File
@@ -0,0 +1,37 @@
package cache
import (
"io"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/internal"
)
func Test_NewInMemory(t *testing.T) {
man := NewInMemory(time.Hour)
cacheName := "test"
cacheVersion := "v1"
cache := man.GetCache(cacheName, cacheVersion)
cacheKey := "test-key"
contentsValue := "some contents to cache"
err := cache.Write(cacheKey, strings.NewReader(contentsValue))
require.NoError(t, err)
rdr, err := cache.Read(cacheKey)
require.NoError(t, err)
defer internal.CloseAndLogError(rdr, cacheKey)
contents, err := io.ReadAll(rdr)
require.NoError(t, err)
require.Equal(t, contentsValue, string(contents))
_, err = cache.Read("otherKey")
require.ErrorIs(t, err, errNotFound)
}
+83
View File
@@ -0,0 +1,83 @@
package cache
import (
"bytes"
"encoding/json"
"fmt"
"path"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
)
// Resolver interface provides a single Resolve method, which will return from cache
// or call the provided resolve function to get the value if not available in cache
type Resolver[T any] interface {
// Resolve attempts to resolve the given key from cache and convert it to the type of the cache,
// or calls the resolver function if unable to resolve a cached value
Resolve(key string, resolver resolverFunc[T]) (T, error)
}
// GetResolver returns a cache resolver for persistent cached data across Syft runs, stored in a unique
// location based on the provided name and versioned by the type
func GetResolver[T any](name, version string) Resolver[T] {
typeHash := hashType[T]()
versionKey := path.Join(version, typeHash)
return &cacheResolver[T]{
name: fmt.Sprintf("%s/%s", name, versionKey),
cache: manager.GetCache(name, versionKey),
}
}
const resolverKeySuffix = ".json"
type resolverFunc[T any] func() (T, error)
type cacheResolver[T any] struct {
name string
cache Cache
}
var _ interface {
Resolver[int]
} = (*cacheResolver[int])(nil)
func (r *cacheResolver[T]) Resolve(key string, resolver resolverFunc[T]) (T, error) {
key += resolverKeySuffix
rdr, err := r.cache.Read(key)
if rdr == nil || err != nil {
return r.resolveAndCache(key, resolver)
}
defer internal.CloseAndLogError(rdr, key)
dec := json.NewDecoder(rdr)
if dec == nil {
log.Tracef("error getting cache json decoder for %s %v: %v", r.name, key, err)
return r.resolveAndCache(key, resolver)
}
var t T
err = dec.Decode(&t)
if err != nil {
log.Tracef("error decoding cached entry for %s %v: %v", r.name, key, err)
return r.resolveAndCache(key, resolver)
}
// no error, able to resolve from cache
return t, nil
}
func (r *cacheResolver[T]) resolveAndCache(key string, resolver func() (T, error)) (T, error) {
t, err := resolver()
if err != nil {
return t, err
}
var data bytes.Buffer
enc := json.NewEncoder(&data)
enc.SetEscapeHTML(false)
err = enc.Encode(t)
if err != nil {
return t, err
}
err = r.cache.Write(key, &data)
return t, err
}
+92
View File
@@ -0,0 +1,92 @@
package cache
import (
"encoding/json"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func Test_Resolver(t *testing.T) {
original := GetManager()
defer SetManager(original)
SetManager(NewInMemory(time.Hour))
type sub struct {
Name string
Value bool
}
type thing struct {
Value string
Values []int
Subs []*sub
}
versionHash := hashType[thing]()
cache := GetManager().GetCache("test", "v7/"+versionHash)
resolver := GetResolver[thing]("test", "v7")
require.NotNil(t, resolver)
require.IsType(t, &cacheResolver[thing]{}, resolver)
cr := resolver.(*cacheResolver[thing])
require.IsType(t, cache, cr.cache)
resolveErrCount := 0
resolveThingErr := func() (thing, error) {
resolveErrCount++
return thing{}, fmt.Errorf("an error")
}
_, err := resolver.Resolve("err", resolveThingErr)
require.ErrorContains(t, err, "an error")
require.Equal(t, 1, resolveErrCount)
_, err = resolver.Resolve("err", resolveThingErr)
require.ErrorContains(t, err, "an error")
require.Equal(t, 2, resolveErrCount)
aThing := thing{
Value: "a value",
Values: []int{7, 8, 9},
Subs: []*sub{
{
Name: "sub1",
Value: true,
},
{
Name: "sub2",
Value: false,
},
},
}
resolveThingCount := 0
resolveThing := func() (thing, error) {
resolveThingCount++
return aThing, nil
}
val, err := resolver.Resolve("thing", resolveThing)
require.NoError(t, err)
require.Equal(t, 1, resolveThingCount)
require.Equal(t, aThing, val)
val, err = resolver.Resolve("thing", resolveThing)
require.NoError(t, err)
require.Equal(t, 1, resolveThingCount)
require.Equal(t, aThing, val)
rdr, err := cache.Read("thing" + resolverKeySuffix)
require.NoError(t, err)
decoder := json.NewDecoder(rdr)
var val2 thing
err = decoder.Decode(&val2)
require.NoError(t, err)
require.Equal(t, aThing, val2)
}
+1 -1
View File
@@ -3,5 +3,5 @@ package internal
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 = "16.0.14"
JSONSchemaVersion = "16.0.15"
)
@@ -21,27 +21,22 @@ func NewDependencyRelationships(resolver file.Resolver, accessor sbomsync.Access
// 3. craft package-to-package relationships for each binary that represent shared library dependencies
//note: we only care about package-to-package relationships
var relIndex *relationship.Index
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
relIndex = relationship.NewIndex(s.Relationships...)
})
return generateRelationships(resolver, accessor, index, relIndex)
return generateRelationships(resolver, accessor, index)
}
func generateRelationships(resolver file.Resolver, accessor sbomsync.Accessor, index *sharedLibraryIndex, relIndex *relationship.Index) []artifact.Relationship {
// read all existing dependencyOf relationships
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
for _, r := range s.Relationships {
if r.Type != artifact.DependencyOfRelationship {
continue
}
relIndex.Track(r)
}
})
func generateRelationships(resolver file.Resolver, accessor sbomsync.Accessor, index *sharedLibraryIndex) []artifact.Relationship {
newRelationships := relationship.NewIndex()
// find all package-to-package relationships for shared library dependencies
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
relIndex := relationship.NewIndex(s.Relationships...)
addRelationship := func(r artifact.Relationship) {
if !relIndex.Contains(r) {
newRelationships.Add(r)
}
}
for _, parentPkg := range s.Artifacts.Packages.Sorted(pkg.BinaryPkg) {
for _, evidentLocation := range parentPkg.Locations.ToSlice() {
if evidentLocation.Annotations[pkg.EvidenceAnnotationKey] != pkg.PrimaryEvidenceAnnotation {
@@ -54,12 +49,12 @@ func generateRelationships(resolver file.Resolver, accessor sbomsync.Accessor, i
continue
}
populateRelationships(exec, parentPkg, resolver, relIndex, index)
populateRelationships(exec, parentPkg, resolver, addRelationship, index)
}
}
})
return relIndex.NewRelationships()
return newRelationships.All()
}
// PackagesToRemove returns a list of binary packages (resolved by the ELF cataloger) that should be removed from the SBOM
@@ -147,7 +142,7 @@ func getBinaryPackagesToDelete(resolver file.Resolver, s *sbom.SBOM) []artifact.
return pkgsToDelete
}
func populateRelationships(exec file.Executable, parentPkg pkg.Package, resolver file.Resolver, relIndex *relationship.Index, index *sharedLibraryIndex) {
func populateRelationships(exec file.Executable, parentPkg pkg.Package, resolver file.Resolver, addRelationship func(artifact.Relationship), index *sharedLibraryIndex) {
for _, libReference := range exec.ImportedLibraries {
// for each library reference, check s.Artifacts.Packages.Sorted(pkg.BinaryPkg) for a binary package that represents that library
// if found, create a relationship between the parent package and the library package
@@ -167,7 +162,7 @@ func populateRelationships(exec file.Executable, parentPkg pkg.Package, resolver
realBaseName := path.Base(loc.RealPath)
pkgCollection := index.owningLibraryPackage(realBaseName)
if pkgCollection.PackageCount() < 1 {
relIndex.Add(
addRelationship(
artifact.Relationship{
From: loc.Coordinates,
To: parentPkg,
@@ -176,7 +171,7 @@ func populateRelationships(exec file.Executable, parentPkg pkg.Package, resolver
)
}
for _, p := range pkgCollection.Sorted() {
relIndex.Add(
addRelationship(
artifact.Relationship{
From: p,
To: parentPkg,
@@ -2,6 +2,7 @@ package binary
import (
"path"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
@@ -328,7 +329,20 @@ func relationshipComparer(x, y []artifact.Relationship) string {
artifact.Relationship{},
file.LocationSet{},
pkg.LicenseSet{},
))
), cmpopts.SortSlices(lessRelationships))
}
func lessRelationships(r1, r2 artifact.Relationship) bool {
c := strings.Compare(string(r1.Type), string(r2.Type))
if c != 0 {
return c < 0
}
c = strings.Compare(string(r1.From.ID()), string(r2.From.ID()))
if c != 0 {
return c < 0
}
c = strings.Compare(string(r1.To.ID()), string(r2.To.ID()))
return c < 0
}
func newAccessor(pkgs []pkg.Package, coordinateIndex map[file.Coordinates]file.Executable, preexistingRelationships []artifact.Relationship) sbomsync.Accessor {
@@ -1,6 +1,7 @@
package relationship
import (
"reflect"
"slices"
"github.com/anchore/syft/internal/sbomsync"
@@ -21,6 +22,10 @@ var (
binaryCatalogerTypes = []pkg.Type{
pkg.BinaryPkg,
}
binaryMetadataTypes = []string{
reflect.TypeOf(pkg.ELFBinaryPackageNoteJSONPayload{}).Name(),
reflect.TypeOf(pkg.BinarySignature{}).Name(),
}
)
func ExcludeBinariesByFileOwnershipOverlap(accessor sbomsync.Accessor) {
@@ -60,5 +65,15 @@ func excludeBinaryByFileOwnershipOverlap(r artifact.Relationship, c *pkg.Collect
return false
}
return slices.Contains(binaryCatalogerTypes, child.Type)
if slices.Contains(binaryCatalogerTypes, child.Type) {
return true
}
if child.Metadata == nil {
return false
}
childMetadataType := reflect.TypeOf(child.Metadata)
return slices.Contains(binaryMetadataTypes, childMetadataType.Name())
}
@@ -12,7 +12,9 @@ func TestExclude(t *testing.T) {
packageB := pkg.Package{Name: "package-a", Type: pkg.PythonPkg}
packageC := pkg.Package{Name: "package-a", Type: pkg.BinaryPkg}
packageD := pkg.Package{Name: "package-d", Type: pkg.BinaryPkg}
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD} {
packageE := pkg.Package{Name: "package-e", Type: pkg.RpmPkg, Metadata: pkg.ELFBinaryPackageNoteJSONPayload{Type: "rpm"}}
packageF := pkg.Package{Name: "package-f", Type: pkg.RpmPkg, Metadata: pkg.BinarySignature{}}
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD, &packageE, &packageF} {
p := p
p.SetID()
}
@@ -43,6 +45,26 @@ func TestExclude(t *testing.T) {
packages: pkg.NewCollection(packageA, packageC),
shouldExclude: true,
},
{
name: "exclusions from os -> elf binary (as RPM)",
relationship: artifact.Relationship{
Type: artifact.OwnershipByFileOverlapRelationship,
From: packageA,
To: packageE,
},
packages: pkg.NewCollection(packageA, packageE),
shouldExclude: true,
},
{
name: "exclusions from os -> binary (masquerading as RPM)",
relationship: artifact.Relationship{
Type: artifact.OwnershipByFileOverlapRelationship,
From: packageA,
To: packageF,
},
packages: pkg.NewCollection(packageA, packageF),
shouldExclude: true,
},
{
name: "no exclusions from python -> binary",
relationship: artifact.Relationship{
+149 -56
View File
@@ -1,88 +1,181 @@
package relationship
import (
"github.com/scylladb/go-set/strset"
"slices"
"strings"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
)
// Index indexes relationships, preventing duplicates
type Index struct {
typesByFromTo map[artifact.ID]map[artifact.ID]*strset.Set
existing []artifact.Relationship
additional []artifact.Relationship
all []*sortableRelationship
fromID map[artifact.ID]*mappedRelationships
toID map[artifact.ID]*mappedRelationships
}
func NewIndex(existing ...artifact.Relationship) *Index {
r := &Index{
typesByFromTo: make(map[artifact.ID]map[artifact.ID]*strset.Set),
}
r.TrackAll(existing...)
return r
// NewIndex returns a new relationship Index
func NewIndex(relationships ...artifact.Relationship) *Index {
out := Index{}
out.Add(relationships...)
return &out
}
func (i *Index) track(r artifact.Relationship) bool {
fromID := r.From.ID()
if _, ok := i.typesByFromTo[fromID]; !ok {
i.typesByFromTo[fromID] = make(map[artifact.ID]*strset.Set)
// Add adds all the given relationships to the index, without adding duplicates
func (i *Index) Add(relationships ...artifact.Relationship) {
if i.fromID == nil {
i.fromID = map[artifact.ID]*mappedRelationships{}
}
if i.toID == nil {
i.toID = map[artifact.ID]*mappedRelationships{}
}
toID := r.To.ID()
if _, ok := i.typesByFromTo[fromID][toID]; !ok {
i.typesByFromTo[fromID][toID] = strset.New()
// store appropriate indexes for stable ordering to minimize ID() calls
for _, r := range relationships {
// prevent duplicates
if i.Contains(r) {
continue
}
fromID := r.From.ID()
toID := r.To.ID()
relationship := &sortableRelationship{
from: fromID,
to: toID,
relationship: r,
}
// add to all relationships
i.all = append(i.all, relationship)
// add from -> to mapping
mapped := i.fromID[fromID]
if mapped == nil {
mapped = &mappedRelationships{}
i.fromID[fromID] = mapped
}
mapped.add(toID, relationship)
// add to -> from mapping
mapped = i.toID[toID]
if mapped == nil {
mapped = &mappedRelationships{}
i.toID[toID] = mapped
}
mapped.add(fromID, relationship)
}
var exists bool
if i.typesByFromTo[fromID][toID].Has(string(r.Type)) {
exists = true
}
i.typesByFromTo[fromID][toID].Add(string(r.Type))
return !exists
}
// Track this relationship as "exists" in the index (this is used to prevent duplicate relationships from being added).
// returns true if the relationship is new to the index, false otherwise.
func (i *Index) Track(r artifact.Relationship) bool {
unique := i.track(r)
if unique {
i.existing = append(i.existing, r)
}
return unique
// From returns all relationships from the given identifiable, with specified types
func (i *Index) From(identifiable artifact.Identifiable, types ...artifact.RelationshipType) []artifact.Relationship {
return toSortedSlice(fromMapped(i.fromID, identifiable), types)
}
// Add a new relationship to the index, returning true if the relationship is new to the index, false otherwise (thus is a duplicate).
func (i *Index) Add(r artifact.Relationship) bool {
if i.track(r) {
i.additional = append(i.additional, r)
return true
// To returns all relationships to the given identifiable, with specified types
func (i *Index) To(identifiable artifact.Identifiable, types ...artifact.RelationshipType) []artifact.Relationship {
return toSortedSlice(fromMapped(i.toID, identifiable), types)
}
// References returns all relationships that reference to or from the given identifiable
func (i *Index) References(identifiable artifact.Identifiable, types ...artifact.RelationshipType) []artifact.Relationship {
return toSortedSlice(append(fromMapped(i.fromID, identifiable), fromMapped(i.toID, identifiable)...), types)
}
// Coordinates returns all coordinates for the provided identifiable for provided relationship types
// If no types are provided, all relationship types are considered.
func (i *Index) Coordinates(identifiable artifact.Identifiable, types ...artifact.RelationshipType) []file.Coordinates {
var coordinates []file.Coordinates
for _, relationship := range i.References(identifiable, types...) {
cords := extractCoordinates(relationship)
coordinates = append(coordinates, cords...)
}
return coordinates
}
// Contains indicates the relationship is present in this index
func (i *Index) Contains(r artifact.Relationship) bool {
if mapped := i.fromID[r.From.ID()]; mapped != nil {
if ids := mapped.typeMap[r.Type]; ids != nil {
return ids[r.To.ID()] != nil
}
}
return false
}
func (i *Index) TrackAll(rs ...artifact.Relationship) {
for _, r := range rs {
i.Track(r)
// All returns a sorted set of relationships matching all types, or all relationships if no types specified
func (i *Index) All(types ...artifact.RelationshipType) []artifact.Relationship {
return toSortedSlice(i.all, types)
}
func fromMapped(idMap map[artifact.ID]*mappedRelationships, identifiable artifact.Identifiable) []*sortableRelationship {
if identifiable == nil || idMap == nil {
return nil
}
}
func (i *Index) AddAll(rs ...artifact.Relationship) {
for _, r := range rs {
i.Add(r)
mapped := idMap[identifiable.ID()]
if mapped == nil {
return nil
}
return mapped.allRelated
}
func (i *Index) NewRelationships() []artifact.Relationship {
return i.additional
func toSortedSlice(relationships []*sortableRelationship, types []artifact.RelationshipType) []artifact.Relationship {
// always return sorted for SBOM stability
slices.SortFunc(relationships, sortFunc)
var out []artifact.Relationship
for _, r := range relationships {
if len(types) == 0 || slices.Contains(types, r.relationship.Type) {
out = append(out, r.relationship)
}
}
return out
}
func (i *Index) ExistingRelationships() []artifact.Relationship {
return i.existing
func extractCoordinates(relationship artifact.Relationship) (results []file.Coordinates) {
if coordinates, exists := relationship.From.(file.Coordinates); exists {
results = append(results, coordinates)
}
if coordinates, exists := relationship.To.(file.Coordinates); exists {
results = append(results, coordinates)
}
return results
}
func (i *Index) AllUniqueRelationships() []artifact.Relationship {
var all []artifact.Relationship
all = append(all, i.existing...)
all = append(all, i.additional...)
return all
type mappedRelationships struct {
typeMap map[artifact.RelationshipType]map[artifact.ID]*sortableRelationship
allRelated []*sortableRelationship
}
func (m *mappedRelationships) add(id artifact.ID, newRelationship *sortableRelationship) {
m.allRelated = append(m.allRelated, newRelationship)
if m.typeMap == nil {
m.typeMap = map[artifact.RelationshipType]map[artifact.ID]*sortableRelationship{}
}
typeMap := m.typeMap[newRelationship.relationship.Type]
if typeMap == nil {
typeMap = map[artifact.ID]*sortableRelationship{}
m.typeMap[newRelationship.relationship.Type] = typeMap
}
typeMap[id] = newRelationship
}
type sortableRelationship struct {
from artifact.ID
to artifact.ID
relationship artifact.Relationship
}
func sortFunc(a, b *sortableRelationship) int {
cmp := strings.Compare(string(a.relationship.Type), string(b.relationship.Type))
if cmp != 0 {
return cmp
}
cmp = strings.Compare(string(a.from), string(b.from))
if cmp != 0 {
return cmp
}
return strings.Compare(string(a.to), string(b.to))
}
+208 -200
View File
@@ -3,223 +3,231 @@ package relationship
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
)
func Test_newRelationshipIndex(t *testing.T) {
from := fakeIdentifiable{id: "from"}
to := fakeIdentifiable{id: "to"}
tests := []struct {
name string
given []artifact.Relationship
track []artifact.Relationship
add []artifact.Relationship
wantExisting []string
wantAdditional []string
}{
{
name: "empty",
},
{
name: "tracks existing relationships",
given: []artifact.Relationship{
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
},
wantExisting: []string{"from [evident-by] to"},
},
{
name: "deduplicate tracked relationships",
given: []artifact.Relationship{
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
},
track: []artifact.Relationship{
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
},
wantExisting: []string{"from [evident-by] to"},
},
{
name: "deduplicate any input relationships",
given: []artifact.Relationship{
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
},
track: []artifact.Relationship{
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
},
add: []artifact.Relationship{
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
},
wantExisting: []string{"from [evident-by] to"},
},
{
name: "deduplicate any added relationships",
add: []artifact.Relationship{
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
{
From: from,
To: to,
Type: artifact.EvidentByRelationship,
},
},
wantAdditional: []string{"from [evident-by] to"},
},
func Test_Index(t *testing.T) {
p1 := pkg.Package{
Name: "pkg-1",
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
idx := NewIndex(tt.given...)
idx.TrackAll(tt.track...)
idx.AddAll(tt.add...)
diffRelationships(t, tt.wantExisting, idx.existing)
diffRelationships(t, tt.wantAdditional, idx.additional)
})
p2 := pkg.Package{
Name: "pkg-2",
}
p3 := pkg.Package{
Name: "pkg-3",
}
c1 := file.Coordinates{
RealPath: "/coords/1",
}
c2 := file.Coordinates{
RealPath: "/coords/2",
}
for _, p := range []*pkg.Package{&p1, &p2, &p3} {
p.SetID()
}
r1 := artifact.Relationship{
From: p1,
To: p2,
Type: artifact.DependencyOfRelationship,
}
r2 := artifact.Relationship{
From: p1,
To: p3,
Type: artifact.DependencyOfRelationship,
}
r3 := artifact.Relationship{
From: p1,
To: c1,
Type: artifact.ContainsRelationship,
}
r4 := artifact.Relationship{
From: p2,
To: c2,
Type: artifact.ContainsRelationship,
}
r5 := artifact.Relationship{
From: p3,
To: c2,
Type: artifact.ContainsRelationship,
}
dup := artifact.Relationship{
From: p3,
To: c2,
Type: artifact.ContainsRelationship,
}
idx := NewIndex(r1, r2, r3, r4, r5, dup)
require.ElementsMatch(t, slice(r1, r2, r3, r4, r5), idx.All())
require.ElementsMatch(t, slice(r1, r4), idx.References(p2))
require.ElementsMatch(t, slice(r4), idx.References(p2, artifact.ContainsRelationship))
require.ElementsMatch(t, slice(r1), idx.To(p2))
require.ElementsMatch(t, []artifact.Relationship(nil), idx.To(p2, artifact.ContainsRelationship))
require.ElementsMatch(t, slice(r4), idx.From(p2))
require.ElementsMatch(t, slice(r4), idx.From(p2, artifact.ContainsRelationship))
}
func diffRelationships(t *testing.T, expected []string, actual []artifact.Relationship) {
if d := cmp.Diff(expected, stringRelationships(actual)); d != "" {
t.Errorf("unexpected relationships (-want, +got): %s", d)
func Test_sortOrder(t *testing.T) {
r1 := artifact.Relationship{
From: id("1"),
To: id("2"),
Type: "1",
}
}
func stringRelationships(relationships []artifact.Relationship) []string {
var result []string
for _, r := range relationships {
result = append(result, string(r.From.ID())+" ["+string(r.Type)+"] "+string(r.To.ID()))
r2 := artifact.Relationship{
From: id("2"),
To: id("3"),
Type: "1",
}
return result
}
func Test_relationshipIndex_track(t *testing.T) {
from := fakeIdentifiable{id: "from"}
to := fakeIdentifiable{id: "to"}
relationship := artifact.Relationship{From: from, To: to, Type: artifact.EvidentByRelationship}
tests := []struct {
name string
existing []artifact.Relationship
given artifact.Relationship
want bool
}{
{
name: "track returns true for a new relationship",
existing: []artifact.Relationship{},
given: relationship,
want: true,
},
{
name: "track returns false for an existing relationship",
existing: []artifact.Relationship{relationship},
given: relationship,
want: false,
},
r3 := artifact.Relationship{
From: id("3"),
To: id("4"),
Type: "1",
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
i := NewIndex(tt.existing...)
if got := i.Track(tt.given); got != tt.want {
t.Errorf("track() = %v, want %v", got, tt.want)
}
})
r4 := artifact.Relationship{
From: id("1"),
To: id("2"),
Type: "2",
}
}
func Test_relationshipIndex_add(t *testing.T) {
from := fakeIdentifiable{id: "from"}
to := fakeIdentifiable{id: "to"}
relationship := artifact.Relationship{From: from, To: to, Type: artifact.EvidentByRelationship}
tests := []struct {
name string
existing []artifact.Relationship
given artifact.Relationship
want bool
}{
{
name: "add returns true for a new relationship",
existing: []artifact.Relationship{},
given: relationship,
want: true,
},
{
name: "add returns false for an existing relationship",
existing: []artifact.Relationship{relationship},
given: relationship,
want: false,
},
r5 := artifact.Relationship{
From: id("2"),
To: id("3"),
Type: "2",
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
i := NewIndex(tt.existing...)
if got := i.Add(tt.given); got != tt.want {
t.Errorf("add() = %v, want %v", got, tt.want)
}
})
dup := artifact.Relationship{
From: id("2"),
To: id("3"),
Type: "2",
}
r6 := artifact.Relationship{
From: id("2"),
To: id("3"),
Type: "3",
}
idx := NewIndex(r5, r2, r6, r4, r1, r3, dup)
require.EqualValues(t, slice(r1, r2, r3, r4, r5, r6), idx.All())
require.EqualValues(t, slice(r1, r4), idx.From(id("1")))
require.EqualValues(t, slice(r2, r5, r6), idx.To(id("3")))
rLast := artifact.Relationship{
From: id("0"),
To: id("3"),
Type: "9999",
}
rFirst := artifact.Relationship{
From: id("0"),
To: id("3"),
Type: "1",
}
rMid := artifact.Relationship{
From: id("0"),
To: id("1"),
Type: "2",
}
idx.Add(rLast, rFirst, rMid)
require.EqualValues(t, slice(rFirst, r1, r2, r3, rMid, r4, r5, r6, rLast), idx.All())
require.EqualValues(t, slice(rFirst, r2, r5, r6, rLast), idx.To(id("3")))
}
type fakeIdentifiable struct {
id string
func Test_Coordinates(t *testing.T) {
p1 := pkg.Package{
Name: "pkg-1",
}
p2 := pkg.Package{
Name: "pkg-2",
}
p3 := pkg.Package{
Name: "pkg-3",
}
c1 := file.Coordinates{
RealPath: "/coords/1",
}
c2 := file.Coordinates{
RealPath: "/coords/2",
}
c3 := file.Coordinates{
RealPath: "/coords/3",
}
c4 := file.Coordinates{
RealPath: "/coords/4",
}
for _, p := range []*pkg.Package{&p1, &p2, &p3} {
p.SetID()
}
r1 := artifact.Relationship{
From: p1,
To: p2,
Type: artifact.DependencyOfRelationship,
}
r2 := artifact.Relationship{
From: p1,
To: p3,
Type: artifact.DependencyOfRelationship,
}
r3 := artifact.Relationship{
From: p1,
To: c1,
Type: artifact.ContainsRelationship,
}
r4 := artifact.Relationship{
From: p2,
To: c2,
Type: artifact.ContainsRelationship,
}
r5 := artifact.Relationship{
From: p3,
To: c1,
Type: artifact.ContainsRelationship,
}
r6 := artifact.Relationship{
From: p3,
To: c2,
Type: artifact.ContainsRelationship,
}
r7 := artifact.Relationship{
From: c1,
To: c3,
Type: artifact.ContainsRelationship,
}
r8 := artifact.Relationship{
From: c3,
To: c4,
Type: artifact.ContainsRelationship,
}
idx := NewIndex(r1, r2, r3, r4, r5, r6, r7, r8)
got := idx.Coordinates(p1)
require.ElementsMatch(t, slice(c1), got)
got = idx.Coordinates(p3)
require.ElementsMatch(t, slice(c1, c2), got)
}
func (f fakeIdentifiable) ID() artifact.ID {
return artifact.ID(f.id)
type id string
func (i id) ID() artifact.ID {
return artifact.ID(i)
}
func slice[T any](values ...T) []T {
return values
}
+2
View File
@@ -29,6 +29,7 @@ import (
"github.com/anchore/syft/syft/pkg/cataloger/rust"
sbomCataloger "github.com/anchore/syft/syft/pkg/cataloger/sbom"
"github.com/anchore/syft/syft/pkg/cataloger/swift"
"github.com/anchore/syft/syft/pkg/cataloger/swipl"
"github.com/anchore/syft/syft/pkg/cataloger/wordpress"
)
@@ -93,6 +94,7 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
newSimplePackageTaskFactory(rust.NewCargoLockCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "rust", "cargo"),
newSimplePackageTaskFactory(swift.NewCocoapodsCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "swift", "cocoapods"),
newSimplePackageTaskFactory(swift.NewSwiftPackageManagerCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "swift", "spm"),
newSimplePackageTaskFactory(swipl.NewSwiplPackCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "swipl", "pack"),
// language-specific package for both image and directory scans (but not necessarily declared) ////////////////////////////////////////
newSimplePackageTaskFactory(dotnet.NewDotnetPortableExecutableCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "dotnet", "c#", "binary"),
+9
View File
@@ -7,3 +7,12 @@ For this reason we've included a copy of all schemas needed to validate `syft` o
to reference local copies of dependent schemas.
You can get the latest schemas from the [CycloneDX specifications repo](https://github.com/CycloneDX/specification/tree/master/schema).
When the spec version is bumped an approach to determining prior modifications is to compare the
prior spec version (e.g. if updating to 1.7, compare the files in this directory against the 1.6
equivalents).
One can also update the schemas and observe the errors in order to make the necessary updates.
At the time of writing, the cyclonedx.xsd needed modifications to link to the local spdx.xsd,
and also to changes the minOccurs for a license tag to 0. (The json schema does not require
modification for the generated file to lint properly, but can simply be copy/pasted).
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+126 -1
View File
@@ -2,7 +2,7 @@
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://cyclonedx.org/schema/spdx"
version="1.0-3.23">
version="1.0-3.24.0">
<xs:simpleType name="licenseId">
<xs:restriction base="xs:string">
@@ -12,6 +12,11 @@
<xs:documentation>BSD Zero Clause License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="3D-Slicer-1.0">
<xs:annotation>
<xs:documentation>3D Slicer License v1.0</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="AAL">
<xs:annotation>
<xs:documentation>Attribution Assurance License</xs:documentation>
@@ -117,6 +122,11 @@
<xs:documentation>Aladdin Free Public License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="AMD-newlib">
<xs:annotation>
<xs:documentation>AMD newlib License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="AMDPLPA">
<xs:annotation>
<xs:documentation>AMD&apos;s plpa_map.c License</xs:documentation>
@@ -147,6 +157,11 @@
<xs:documentation>ANTLR Software Rights Notice with license fallback</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="any-OSI">
<xs:annotation>
<xs:documentation>Any OSI License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Apache-1.0">
<xs:annotation>
<xs:documentation>Apache License 1.0</xs:documentation>
@@ -322,6 +337,11 @@
<xs:documentation>BSD 2-Clause - Ian Darwin variant</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="BSD-2-Clause-first-lines">
<xs:annotation>
<xs:documentation>BSD 2-Clause - first lines requirement</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="BSD-2-Clause-FreeBSD">
<xs:annotation>
<xs:documentation>BSD 2-Clause FreeBSD License</xs:documentation>
@@ -522,6 +542,11 @@
<xs:documentation>Caldera License (without preamble)</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Catharon">
<xs:annotation>
<xs:documentation>Catharon License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="CATOSL-1.1">
<xs:annotation>
<xs:documentation>Computer Associates Trusted Open Source License 1.1</xs:documentation>
@@ -1002,6 +1027,11 @@
<xs:documentation>curl License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="cve-tou">
<xs:annotation>
<xs:documentation>Common Vulnerability Enumeration ToU License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="D-FSL-1.0">
<xs:annotation>
<xs:documentation>Deutsche Freie Software Lizenz</xs:documentation>
@@ -1482,6 +1512,11 @@
<xs:documentation>gtkbook License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Gutmann">
<xs:annotation>
<xs:documentation>Gutmann License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HaskellReport">
<xs:annotation>
<xs:documentation>Haskell Language Report License</xs:documentation>
@@ -1532,11 +1567,21 @@
<xs:documentation>HPND with US Government export control warning</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-export-US-acknowledgement">
<xs:annotation>
<xs:documentation>HPND with US Government export control warning and acknowledgment</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-export-US-modify">
<xs:annotation>
<xs:documentation>HPND with US Government export control warning and modification rqmt</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-export2-US">
<xs:annotation>
<xs:documentation>HPND with US Government export control and 2 disclaimers</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-Fenneberg-Livingston">
<xs:annotation>
<xs:documentation>Historical Permission Notice and Disclaimer - Fenneberg-Livingston variant</xs:documentation>
@@ -1547,6 +1592,11 @@
<xs:documentation>Historical Permission Notice and Disclaimer - INRIA-IMAG variant</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-Intel">
<xs:annotation>
<xs:documentation>Historical Permission Notice and Disclaimer - Intel variant</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-Kevlin-Henney">
<xs:annotation>
<xs:documentation>Historical Permission Notice and Disclaimer - Kevlin Henney variant</xs:documentation>
@@ -1557,6 +1607,11 @@
<xs:documentation>Historical Permission Notice and Disclaimer - Markus Kuhn variant</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-merchantability-variant">
<xs:annotation>
<xs:documentation>Historical Permission Notice and Disclaimer - merchantability variant</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-MIT-disclaimer">
<xs:annotation>
<xs:documentation>Historical Permission Notice and Disclaimer with MIT disclaimer</xs:documentation>
@@ -1587,11 +1642,21 @@
<xs:documentation>HPND sell variant with MIT disclaimer</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-sell-variant-MIT-disclaimer-rev">
<xs:annotation>
<xs:documentation>HPND sell variant with MIT disclaimer - reverse</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-UC">
<xs:annotation>
<xs:documentation>Historical Permission Notice and Disclaimer - University of California variant</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HPND-UC-export-US">
<xs:annotation>
<xs:documentation>Historical Permission Notice and Disclaimer - University of California, US export warning</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HTMLTIDY">
<xs:annotation>
<xs:documentation>HTML Tidy License</xs:documentation>
@@ -2027,6 +2092,11 @@
<xs:documentation>MIT Festival Variant</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="MIT-Khronos-old">
<xs:annotation>
<xs:documentation>MIT Khronos - old variant</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="MIT-Modern-Variant">
<xs:annotation>
<xs:documentation>MIT License Modern Variant</xs:documentation>
@@ -2162,11 +2232,21 @@
<xs:documentation>Net Boolean Public License v1</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NCBI-PD">
<xs:annotation>
<xs:documentation>NCBI Public Domain Notice</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NCGL-UK-2.0">
<xs:annotation>
<xs:documentation>Non-Commercial Government Licence</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NCL">
<xs:annotation>
<xs:documentation>NCL Source Code License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NCSA">
<xs:annotation>
<xs:documentation>University of Illinois/NCSA Open Source License</xs:documentation>
@@ -2282,6 +2362,11 @@
<xs:documentation>Open Use of Data Agreement v1.0</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="OAR">
<xs:annotation>
<xs:documentation>OAR License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="OCCT-PL">
<xs:annotation>
<xs:documentation>Open CASCADE Technology Public License</xs:documentation>
@@ -2562,6 +2647,11 @@
<xs:documentation>Pixar License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="pkgconf">
<xs:annotation>
<xs:documentation>pkgconf License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Plexus">
<xs:annotation>
<xs:documentation>Plexus Classworlds License</xs:documentation>
@@ -2587,6 +2677,11 @@
<xs:documentation>PostgreSQL License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="PPL">
<xs:annotation>
<xs:documentation>Peer Production License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="PSF-2.0">
<xs:annotation>
<xs:documentation>Python Software Foundation License 2.0</xs:documentation>
@@ -2862,6 +2957,11 @@
<xs:documentation>Sun PPP License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Sun-PPP-2000">
<xs:annotation>
<xs:documentation>Sun PPP License (2000)</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="SunPro">
<xs:annotation>
<xs:documentation>SunPro License</xs:documentation>
@@ -2907,6 +3007,11 @@
<xs:documentation>Transitive Grace Period Public Licence 1.0</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="threeparttable">
<xs:annotation>
<xs:documentation>threeparttable License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="TMate">
<xs:annotation>
<xs:documentation>TMate Open Source License</xs:documentation>
@@ -3132,6 +3237,11 @@
<xs:documentation>XSkat License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="xzoom">
<xs:annotation>
<xs:documentation>xzoom License</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="YPL-1.0">
<xs:annotation>
<xs:documentation>Yahoo! Public License v1.0</xs:documentation>
@@ -3203,6 +3313,11 @@
<xs:documentation>Asterisk exception</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Asterisk-linking-protocols-exception">
<xs:annotation>
<xs:documentation>Asterisk linking protocols exception</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Autoconf-exception-2.0">
<xs:annotation>
<xs:documentation>Autoconf exception 2.0</xs:documentation>
@@ -3438,6 +3553,11 @@
<xs:documentation>OpenVPN OpenSSL Exception</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="PCRE2-exception">
<xs:annotation>
<xs:documentation>PCRE2 exception</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="PS-or-PDF-font-exception-20170817">
<xs:annotation>
<xs:documentation>PS/PDF font exception (2017-08-17)</xs:documentation>
@@ -3463,6 +3583,11 @@
<xs:documentation>Qwt exception 1.0</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="RRDtool-FLOSS-exception-2.0">
<xs:annotation>
<xs:documentation>RRDtool FLOSS exception 2.0</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="SANE-exception">
<xs:annotation>
<xs:documentation>SANE Exception</xs:documentation>
File diff suppressed because it is too large Load Diff
+46 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "anchore.io/schema/syft/json/16.0.14/document",
"$id": "anchore.io/schema/syft/json/16.0.15/document",
"$ref": "#/$defs/Document",
"$defs": {
"AlpmDbEntry": {
@@ -1608,6 +1608,9 @@
{
"$ref": "#/$defs/SwiftPackageManagerLockEntry"
},
{
"$ref": "#/$defs/SwiplpackPackage"
},
{
"$ref": "#/$defs/WordpressPluginEntry"
}
@@ -2504,6 +2507,48 @@
"revision"
]
},
"SwiplpackPackage": {
"properties": {
"name": {
"type": "string"
},
"version": {
"type": "string"
},
"author": {
"type": "string"
},
"authorEmail": {
"type": "string"
},
"packager": {
"type": "string"
},
"packagerEmail": {
"type": "string"
},
"homepage": {
"type": "string"
},
"dependencies": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object",
"required": [
"name",
"version",
"author",
"authorEmail",
"packager",
"packagerEmail",
"homepage",
"dependencies"
]
},
"WordpressPluginEntry": {
"properties": {
"pluginInstallDirectory": {
@@ -64,6 +64,28 @@ func TestBySourceThenSpecificity(t *testing.T) {
Must("cpe:2.3:a:some:package:*:*:*:*:*:*:*:*", "some-unknown-source"),
},
},
{
name: "lexical sorting on equal sources puts escaped characters later",
input: []CPE{
Must("cpe:2.3:a:jenkins:pipeline\\\\:_supporting_apis:865.v43e78cc44e0d:*:*:*:*:jenkins:*:*", "nvd-cpe-dictionary"),
Must("cpe:2.3:a:jenkins:pipeline_supporting_apis:865.v43e78cc44e0d:*:*:*:*:jenkins:*:*", "nvd-cpe-dictionary"),
},
want: []CPE{
Must("cpe:2.3:a:jenkins:pipeline_supporting_apis:865.v43e78cc44e0d:*:*:*:*:jenkins:*:*", "nvd-cpe-dictionary"),
Must("cpe:2.3:a:jenkins:pipeline\\\\:_supporting_apis:865.v43e78cc44e0d:*:*:*:*:jenkins:*:*", "nvd-cpe-dictionary"),
},
},
{
name: "lexical sorting on equal sources puts more specific attributes earlier",
input: []CPE{
Must("cpe:2.3:a:jenkins:mailer:472.vf7c289a_4b_420:*:*:*:*:*:*:*", "nvd-cpe-dictionary"),
Must("cpe:2.3:a:jenkins:mailer:472.vf7c289a_4b_420:*:*:*:*:jenkins:*:*", "nvd-cpe-dictionary"),
},
want: []CPE{
Must("cpe:2.3:a:jenkins:mailer:472.vf7c289a_4b_420:*:*:*:*:jenkins:*:*", "nvd-cpe-dictionary"),
Must("cpe:2.3:a:jenkins:mailer:472.vf7c289a_4b_420:*:*:*:*:*:*:*", "nvd-cpe-dictionary"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+1 -1
View File
@@ -21,7 +21,7 @@ type LicenseEvidence struct {
func NewLicense(value string) License {
spdxExpression, err := license.ParseExpression(value)
if err != nil {
log.Trace("unable to parse license expression: %s, %w", value, err)
log.WithFields("error", err, "value", value).Trace("unable to parse license expression")
}
return License{
@@ -16,6 +16,7 @@ import (
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/mimetype"
"github.com/anchore/syft/internal/relationship"
"github.com/anchore/syft/internal/spdxlicense"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
@@ -45,9 +46,10 @@ const (
func ToFormatModel(s sbom.SBOM) *spdx.Document {
name, namespace := helpers.DocumentNameAndNamespace(s.Source, s.Descriptor)
packages := toPackages(s.Artifacts.Packages, s)
rels := relationship.NewIndex(s.Relationships...)
packages := toPackages(rels, s.Artifacts.Packages, s)
relationships := toRelationships(s.RelationshipsSorted())
allRelationships := toRelationships(rels.All())
// for valid SPDX we need a document describes relationship
describesID := spdx.ElementID("DOCUMENT")
@@ -57,7 +59,7 @@ func ToFormatModel(s sbom.SBOM) *spdx.Document {
describesID = rootPackage.PackageSPDXIdentifier
// add all relationships from the document root to all other packages
relationships = append(relationships, toRootRelationships(rootPackage, packages)...)
allRelationships = append(allRelationships, toRootRelationships(rootPackage, packages)...)
// append the root package
packages = append(packages, rootPackage)
@@ -75,7 +77,7 @@ func ToFormatModel(s sbom.SBOM) *spdx.Document {
}
// add the root document relationship
relationships = append(relationships, documentDescribesRelationship)
allRelationships = append(allRelationships, documentDescribesRelationship)
return &spdx.Document{
// 6.1: SPDX Version; should be in the format "SPDX-x.x"
@@ -150,7 +152,7 @@ func ToFormatModel(s sbom.SBOM) *spdx.Document {
},
Packages: packages,
Files: toFiles(s),
Relationships: relationships,
Relationships: allRelationships,
OtherLicenses: toOtherLicenses(s.Artifacts.Packages),
}
}
@@ -302,7 +304,7 @@ func toSPDXID(identifiable artifact.Identifiable) spdx.ElementID {
// packages populates all Package Information from the package Collection (see https://spdx.github.io/spdx-spec/3-package-information/)
//
//nolint:funlen
func toPackages(catalog *pkg.Collection, sbom sbom.SBOM) (results []*spdx.Package) {
func toPackages(rels *relationship.Index, catalog *pkg.Collection, sbom sbom.SBOM) (results []*spdx.Package) {
for _, p := range catalog.Sorted() {
// name should be guaranteed to be unique, but semantically useful and stable
id := toSPDXID(p)
@@ -318,7 +320,7 @@ func toPackages(catalog *pkg.Collection, sbom sbom.SBOM) (results []*spdx.Packag
// 2. syft has generated a sha1 digest for the package's contents
packageChecksums, filesAnalyzed := toPackageChecksums(p)
packageVerificationCode := newPackageVerificationCode(p, sbom)
packageVerificationCode := newPackageVerificationCode(rels, p, sbom)
if packageVerificationCode != nil {
filesAnalyzed = true
}
@@ -744,12 +746,12 @@ func toOtherLicenses(catalog *pkg.Collection) []*spdx.OtherLicense {
// f file is an "excludes" file, skip it /* exclude SPDX analysis file(s) */
// see: https://spdx.github.io/spdx-spec/v2.3/package-information/#79-package-verification-code-field
// the above link contains the SPDX algorithm for a package verification code
func newPackageVerificationCode(p pkg.Package, sbom sbom.SBOM) *spdx.PackageVerificationCode {
func newPackageVerificationCode(rels *relationship.Index, p pkg.Package, sbom sbom.SBOM) *spdx.PackageVerificationCode {
// key off of the contains relationship;
// spdx validator will fail if a package claims to contain a file but no sha1 provided
// if a sha1 for a file is provided then the validator will fail if the package does not have
// a package verification code
coordinates := sbom.CoordinatesForPackage(p, artifact.ContainsRelationship)
coordinates := rels.Coordinates(p, artifact.ContainsRelationship)
var digests []file.Digest
for _, c := range coordinates {
digest := sbom.Artifacts.FileDigests[c]
@@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/internal/relationship"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/format/internal/spdxutil/helpers"
@@ -665,7 +666,7 @@ func Test_H1Digest(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
catalog := pkg.NewCollection(test.pkg)
pkgs := toPackages(catalog, s)
pkgs := toPackages(relationship.NewIndex(), catalog, s)
require.Len(t, pkgs, 1)
for _, p := range pkgs {
if test.expectedDigest == "" {
@@ -0,0 +1,59 @@
{
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:5208fea9-73dd-4624-b596-69fddccdb9e7",
"version": 1,
"metadata": {
"timestamp": "2023-09-29T12:02:02-04:00",
"tools": [
{
"vendor": "anchore",
"name": "syft",
"version": "[not provided]"
}
],
"component": {
"bom-ref": "a0ff99a6af10f11f",
"type": "file",
"name": "go.mod",
"version": "sha256:sha256:dc333f342905248a52e424d8dfd061251d01867d01a4f9d7397144a775ff9ebd"
}
},
"components": [
{
"bom-ref": "pkg:golang/github.com/wagoodman/go-partybus@v0.0.0-20230516145632-8ccac152c651?package-id=2ff71a67fb024c86",
"type": "library",
"name": "github.com/wagoodman/go-partybus",
"version": "v0.0.0-20230516145632-8ccac152c651",
"cpe": "cpe:2.3:a:wagoodman:go-partybus:v0.0.0-20230516145632-8ccac152c651:*:*:*:*:*:*:*",
"purl": "pkg:golang/github.com/wagoodman/go-partybus@v0.0.0-20230516145632-8ccac152c651",
"properties": [
{
"name": "syft:package:foundBy",
"value": "go-module-file-cataloger"
},
{
"name": "syft:package:language",
"value": "go"
},
{
"name": "syft:package:metadataType",
"value": "GolangModMetadata"
},
{
"name": "syft:package:type",
"value": "go-module"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:wagoodman:go_partybus:v0.0.0-20230516145632-8ccac152c651:*:*:*:*:*:*:*"
},
{
"name": "syft:location:0:path",
"value": "/go.mod"
}
]
}
]
}
@@ -0,0 +1,28 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"version": 1,
"components": [
{
"type": "library",
"group": "io.netty",
"name": "netty-codec-http2",
"version": "4.1.73.Final",
"properties": [
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:codec:codec:4.1.73.Final:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:codec:netty-codec-http2:4.1.73.Final:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:codec:netty_codec_http2:4.1.73.Final:*:*:*:*:*:*:*"
}
]
}
],
"serialNumber": "urn:uuid:3eb5ec7a-cb05-4339-b873-e27b1c1efaba"
}
@@ -1,7 +1,7 @@
{
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"specVersion": "1.6",
"serialNumber": "urn:uuid:redacted",
"version": 1,
"metadata": {
@@ -1,7 +1,7 @@
{
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"specVersion": "1.6",
"serialNumber": "urn:uuid:redacted",
"version": 1,
"metadata": {
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.6" serialNumber="urn:uuid:098e8516-ecd5-4130-9d5f-c32ba1ddb0dd" version="1">
<metadata>
<timestamp>2023-09-29T11:48:10-04:00</timestamp>
<tools>
<tool>
<vendor>anchore</vendor>
<name>syft</name>
<version>[not provided]</version>
</tool>
</tools>
<component bom-ref="a0ff99a6af10f11f" type="file">
<name>go.mod</name>
<version>sha256:sha256:dc333f342905248a52e424d8dfd061251d01867d01a4f9d7397144a775ff9ebd</version>
</component>
</metadata>
<components>
<component bom-ref="pkg:golang/github.com/wagoodman/go-partybus@v0.0.0-20230516145632-8ccac152c651?package-id=2ff71a67fb024c86" type="library">
<name>github.com/wagoodman/go-partybus</name>
<version>v0.0.0-20230516145632-8ccac152c651</version>
<cpe>cpe:2.3:a:wagoodman:go-partybus:v0.0.0-20230516145632-8ccac152c651:*:*:*:*:*:*:*</cpe>
<purl>pkg:golang/github.com/wagoodman/go-partybus@v0.0.0-20230516145632-8ccac152c651</purl>
<properties>
<property name="syft:package:foundBy">go-module-file-cataloger</property>
<property name="syft:package:language">go</property>
<property name="syft:package:metadataType">GolangModMetadata</property>
<property name="syft:package:type">go-module</property>
<property name="syft:cpe23">cpe:2.3:a:wagoodman:go_partybus:v0.0.0-20230516145632-8ccac152c651:*:*:*:*:*:*:*</property>
<property name="syft:location:0:path">/go.mod</property>
</properties>
</component>
</components>
</bom>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.5" serialNumber="redacted" version="1">
<bom xmlns="http://cyclonedx.org/schema/bom/1.6" serialNumber="redacted" version="1">
<metadata>
<timestamp>redacted</timestamp>
<tools>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.5" serialNumber="redacted" version="1">
<bom xmlns="http://cyclonedx.org/schema/bom/1.6" serialNumber="redacted" version="1">
<metadata>
<timestamp>redacted</timestamp>
<tools>
@@ -9,7 +9,7 @@ import (
"github.com/anchore/syft/syft/sbom"
)
const DefaultVersion = "1.5"
const DefaultVersion = "1.6"
type Encoder struct {
version cyclonedx.SpecVersion
@@ -19,6 +19,7 @@ func SupportedVersions(id sbom.FormatID) []string {
"1.3",
"1.4",
"1.5",
"1.6",
}
if id != JSONFormatID {
@@ -43,6 +44,8 @@ func SpecVersionFromString(v string) (cyclonedx.SpecVersion, error) {
return cyclonedx.SpecVersion1_4, nil
case "1.5":
return cyclonedx.SpecVersion1_5, nil
case "1.6":
return cyclonedx.SpecVersion1_6, nil
}
return -1, fmt.Errorf("unsupported CycloneDX version %q", v)
}
@@ -61,6 +64,8 @@ func VersionFromSpecVersion(spec cyclonedx.SpecVersion) string {
return "1.4"
case cyclonedx.SpecVersion1_5:
return "1.5"
case cyclonedx.SpecVersion1_6:
return "1.6"
}
return ""
}
@@ -22,6 +22,10 @@ func DownloadLocation(p pkg.Package) string {
return NoneIfEmpty(metadata.URL)
case pkg.NpmPackageLockEntry:
return NoneIfEmpty(metadata.Resolved)
case pkg.PhpComposerLockEntry:
return NoneIfEmpty(metadata.Dist.URL)
case pkg.PhpComposerInstalledEntry:
return NoneIfEmpty(metadata.Dist.URL)
}
}
return NOASSERTION
@@ -64,6 +64,50 @@ func Test_DownloadLocation(t *testing.T) {
},
expected: NONE,
},
{
name: "from php installed.json",
input: pkg.Package{
Metadata: pkg.PhpComposerInstalledEntry{
Dist: pkg.PhpComposerExternalReference{
URL: "http://package-lock.test",
},
},
},
expected: "http://package-lock.test",
},
{
name: "empty",
input: pkg.Package{
Metadata: pkg.PhpComposerInstalledEntry{
Dist: pkg.PhpComposerExternalReference{
URL: "",
},
},
},
expected: "NONE",
},
{
name: "from php composer.lock",
input: pkg.Package{
Metadata: pkg.PhpComposerLockEntry{
Dist: pkg.PhpComposerExternalReference{
URL: "http://package-lock.test",
},
},
},
expected: "http://package-lock.test",
},
{
name: "empty",
input: pkg.Package{
Metadata: pkg.PhpComposerLockEntry{
Dist: pkg.PhpComposerExternalReference{
URL: "",
},
},
},
expected: "NONE",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
@@ -56,6 +56,10 @@ func Originator(p pkg.Package) (typ string, author string) { // nolint: funlen
if author == "" {
author = metadata.Manifest.Main.MustGet("Implementation-Vendor")
}
// Vendor is specified, hence set 'Organization' as the PackageSupplier
if author != "" {
typ = orgType
}
}
case pkg.LinuxKernelModule:
@@ -103,6 +107,8 @@ func Originator(p pkg.Package) (typ string, author string) { // nolint: funlen
// it seems that the vast majority of the time the author is an org, not a person
typ = orgType
author = metadata.Author
case pkg.SwiplPackEntry:
author = formatPersonOrOrg(metadata.Author, metadata.AuthorEmail)
}
if typ == "" && author != "" {
@@ -144,6 +150,10 @@ func Supplier(p pkg.Package) (typ string, author string) {
author = metadata.Packager
}
if metadata, ok := p.Metadata.(pkg.SwiplPackEntry); ok {
author = formatPersonOrOrg(metadata.Packager, metadata.PackagerEmail)
}
if author == "" {
// TODO: this uses the Originator function for now until a better distinction can be made for supplier
return Originator(p)
@@ -40,6 +40,7 @@ func Test_OriginatorSupplier(t *testing.T) {
pkg.RustBinaryAuditEntry{},
pkg.RustCargoLockEntry{},
pkg.SwiftPackageManagerResolvedEntry{},
pkg.SwiplPackEntry{},
pkg.YarnLockEntry{},
)
tests := []struct {
@@ -137,8 +138,8 @@ func Test_OriginatorSupplier(t *testing.T) {
},
},
},
originator: "Person: auth-spec",
supplier: "Person: auth-spec",
originator: "Organization: auth-spec",
supplier: "Organization: auth-spec",
},
{
name: "from java -- fallback to impl vendor in main manifest section",
@@ -154,8 +155,8 @@ func Test_OriginatorSupplier(t *testing.T) {
},
},
},
originator: "Person: auth-impl",
supplier: "Person: auth-impl",
originator: "Organization: auth-impl",
supplier: "Organization: auth-impl",
},
{
name: "from java -- non-main manifest sections ignored",
@@ -336,6 +337,19 @@ func Test_OriginatorSupplier(t *testing.T) {
originator: "Organization: auth",
supplier: "Organization: auth",
},
{
name: "from swipl pack",
input: pkg.Package{
Metadata: pkg.SwiplPackEntry{
Author: "auth",
AuthorEmail: "auth@auth.gov",
Packager: "me",
PackagerEmail: "me@auth.com",
},
},
originator: "Person: auth (auth@auth.gov)",
supplier: "Person: me (me@auth.com)",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
@@ -62,6 +62,8 @@ func SourceInfo(p pkg.Package) string {
answer = "acquired package info from Rockspec package file"
case pkg.SwiftPkg:
answer = "acquired package info from resolved Swift package manifest"
case pkg.SwiplPackPkg:
answer = "acquired package info from SWI Prolo pack package file"
case pkg.GithubActionPkg, pkg.GithubActionWorkflowPkg:
answer = "acquired package info from GitHub Actions workflow file or composite action file"
case pkg.WordpressPluginPkg:
@@ -263,6 +263,14 @@ func Test_SourceInfo(t *testing.T) {
"from resolved Swift package manifest",
},
},
{
input: pkg.Package{
Type: pkg.SwiplPackPkg,
},
expected: []string{
"acquired package info from SWI Prolo pack package file",
},
},
{
input: pkg.Package{
Type: pkg.GithubActionPkg,
@@ -49,6 +49,7 @@ func AllTypes() []any {
pkg.RustBinaryAuditEntry{},
pkg.RustCargoLockEntry{},
pkg.SwiftPackageManagerResolvedEntry{},
pkg.SwiplPackEntry{},
pkg.WordpressPluginEntry{},
pkg.YarnLockEntry{},
}
+1
View File
@@ -102,6 +102,7 @@ var jsonTypes = makeJSONTypes(
jsonNames(pkg.RpmDBEntry{}, "rpm-db-entry", "RpmMetadata", "RpmdbMetadata"),
jsonNamesWithoutLookup(pkg.RpmArchive{}, "rpm-archive", "RpmMetadata"), // the legacy value is split into two types, where the other is preferred
jsonNames(pkg.SwiftPackageManagerResolvedEntry{}, "swift-package-manager-lock-entry", "SwiftPackageManagerMetadata"),
jsonNames(pkg.SwiplPackEntry{}, "swiplpack-package"),
jsonNames(pkg.RustCargoLockEntry{}, "rust-cargo-lock-entry", "RustCargoPackageMetadata"),
jsonNamesWithoutLookup(pkg.RustBinaryAuditEntry{}, "rust-cargo-audit-entry", "RustCargoPackageMetadata"), // the legacy value is split into two types, where the other is preferred
jsonNames(pkg.WordpressPluginEntry{}, "wordpress-plugin-entry", "WordpressMetadata"),
@@ -473,12 +473,6 @@ func Test_JSONName_JSONLegacyName(t *testing.T) {
expectedJSONName: "rpm-archive",
expectedLegacyName: "RpmMetadata", // note: conflicts with <=v11.x schema for "rpm-db-entry" metadata type
},
{
name: "SwiftPackageManagerMetadata",
metadata: pkg.SwiftPackageManagerResolvedEntry{},
expectedJSONName: "swift-package-manager-lock-entry",
expectedLegacyName: "SwiftPackageManagerMetadata",
},
{
name: "CargoPackageMetadata",
metadata: pkg.RustCargoLockEntry{},
@@ -48,6 +48,17 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
Metadata: metadata("arangodb-binary"),
},
},
{
logicalFixture: "arangodb/3.12.0-2/linux-amd64",
expected: pkg.Package{
Name: "arangodb",
Version: "3.12.0-2",
Type: "binary",
PURL: "pkg:generic/arangodb@3.12.0-2",
Locations: locations("arangosh"),
Metadata: metadata("arangodb-binary"),
},
},
{
logicalFixture: "postgres/15beta4/linux-amd64",
expected: pkg.Package{
@@ -193,6 +204,17 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
Metadata: metadata("traefik-binary"),
},
},
{
logicalFixture: "traefik/3.0.4/linux-riscv64",
expected: pkg.Package{
Name: "traefik",
Version: "3.0.4",
Type: "binary",
PURL: "pkg:generic/traefik@3.0.4",
Locations: locations("traefik"),
Metadata: metadata("traefik-binary"),
},
},
{
logicalFixture: "memcached/1.6.18/linux-amd64",
expected: pkg.Package{
@@ -896,6 +918,28 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
Metadata: metadata("erlang-library"),
},
},
{
logicalFixture: "erlang/27.0/linux-amd64",
expected: pkg.Package{
Name: "erlang",
Version: "27.0",
Type: "binary",
PURL: "pkg:generic/erlang@27.0",
Locations: locations("beam.smp"),
Metadata: metadata("erlang-alpine-binary"),
},
},
{
logicalFixture: "swipl/9.3.8/linux-amd64",
expected: pkg.Package{
Name: "swipl",
Version: "9.3.8",
Type: "binary",
PURL: "pkg:generic/swipl@9.3.8",
Locations: locations("swipl"),
Metadata: metadata("swipl-binary"),
},
},
{
logicalFixture: "nginx/1.25.1/linux-amd64",
expected: pkg.Package{
+30 -2
View File
@@ -263,7 +263,8 @@ func DefaultClassifiers() []Classifier {
EvidenceMatcher: FileContentsVersionMatcher(
// [NUL]v1.7.34[NUL]
// [NUL]2.9.6[NUL]
`(?m)(\x00|\x{FFFD})v?(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-alpha[0-9]|-beta[0-9]|-rc[0-9])?)\x00`),
// 3.0.4[NUL]
`(?m)(\x00|\x{FFFD})?v?(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-alpha[0-9]|-beta[0-9]|-rc[0-9])?)\x00`),
Package: "traefik",
PURL: mustPURL("pkg:generic/traefik@version"),
CPEs: singleCPE("cpe:2.3:a:traefik:traefik:*:*:*:*:*:*:*:*"),
@@ -272,7 +273,7 @@ func DefaultClassifiers() []Classifier {
Class: "arangodb-binary",
FileGlob: "**/arangosh",
EvidenceMatcher: FileContentsVersionMatcher(
`(?m)ArangoDB\s\x00*(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\s\[linux\]`),
`(?m)\x00*(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?)\s\[linux\]`),
Package: "arangodb",
PURL: mustPURL("pkg:generic/arangodb@version"),
CPEs: singleCPE("cpe:2.3:a:arangodb:arangodb:*:*:*:*:*:*:*:*"),
@@ -393,6 +394,23 @@ func DefaultClassifiers() []Classifier {
PURL: mustPURL("pkg:generic/erlang@version"),
CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"),
},
{
Class: "erlang-alpine-binary",
FileGlob: "**/beam.smp",
EvidenceMatcher: evidenceMatchers(
FileContentsVersionMatcher(
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
),
FileContentsVersionMatcher(
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
),
),
Package: "erlang",
PURL: mustPURL("pkg:generic/erlang@version"),
CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"),
},
{
Class: "erlang-library",
FileGlob: "**/liberts_internal.a",
@@ -410,6 +428,16 @@ func DefaultClassifiers() []Classifier {
PURL: mustPURL("pkg:generic/erlang@version"),
CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"),
},
{
Class: "swipl-binary",
FileGlob: "**/swipl",
EvidenceMatcher: FileContentsVersionMatcher(
`(?m)swipl-(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\/`,
),
Package: "swipl",
PURL: mustPURL("pkg:generic/swipl@version"),
CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"),
},
{
Class: "consul-binary",
FileGlob: "**/consul",
+19 -3
View File
@@ -13,7 +13,7 @@ func newELFPackage(metadata elfBinaryPackageNotes, locations file.LocationSet) p
Version: metadata.Version,
Licenses: pkg.NewLicenseSet(pkg.NewLicense(metadata.License)),
PURL: packageURL(metadata),
Type: pkg.BinaryPkg,
Type: pkgType(metadata.Type),
Locations: locations,
Metadata: metadata.ELFBinaryPackageNoteJSONPayload,
}
@@ -67,6 +67,8 @@ func packageURL(metadata elfBinaryPackageNotes) string {
).ToString()
}
const alpmType = "alpm"
func purlDistroType(ty string) string {
switch ty {
case "rpm":
@@ -75,8 +77,22 @@ func purlDistroType(ty string) string {
return packageurl.TypeDebian
case "apk":
return packageurl.TypeAlpine
case "alpm":
return "alpm"
case alpmType:
return alpmType
}
return packageurl.TypeGeneric
}
func pkgType(ty string) pkg.Type {
switch ty {
case "rpm":
return pkg.RpmPkg
case "deb":
return pkg.DebPkg
case "apk":
return pkg.ApkPkg
case alpmType:
return pkg.AlpmPkg
}
return pkg.BinaryPkg
}
@@ -70,14 +70,14 @@ func Test_ELF_Package_Cataloger(t *testing.T) {
expected: []pkg.Package{
{
Name: "coreutils",
Version: "9.5-1.fc41",
PURL: "pkg:rpm/fedora/coreutils@9.5-1.fc41?distro=fedora-40",
Version: "9.5-3.fc41",
PURL: "pkg:rpm/fedora/coreutils@9.5-3.fc41?distro=fedora-40",
Locations: file.NewLocationSet(
file.NewLocation("/sha256sum").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
file.NewLocation("/sha1sum").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
),
Licenses: pkg.NewLicenseSet(),
Type: pkg.BinaryPkg,
Type: pkg.RpmPkg,
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
Type: "rpm",
Architecture: "x86_64",
@@ -99,7 +99,7 @@ func Test_ELF_Package_Cataloger(t *testing.T) {
file.NewLocation("/sha1sum").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
),
Licenses: pkg.NewLicenseSet(),
Type: pkg.BinaryPkg,
Type: pkg.RpmPkg,
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
Type: "rpm",
Architecture: "arm",
@@ -0,0 +1,9 @@
name: beam.smp
offset: 6378906
length: 140
snippetSha256: 186c882decc4160bfcfbdddaee08e8364675c795d3e85697422fbd7218452ee2
fileSha256: f84f0ffc2e397abcf5f081b865e241017b1793c2ec38f5136bff4e5e21ffdad7
### byte snippet to follow ###
ied by configure */
#define ERTS_EMU_CMDLINE_FLAGS " -fno-strict-aliasing -fno-common -g -O2 -I/usr/src/otp_src_27.0/erts/x86_64-pc-linux-mu
@@ -63,6 +63,21 @@ from-images:
paths:
- /usr/local/lib/erlang/erts-14.2.4/lib/internal/liberts_internal.a
- name: erlang
version: 27.0
images:
- ref: erlang:27.0.0.0-alpine@sha256:82064a65eb1f9901a479d8ada5f622be3bfac8b474dfc876dc00c28fdef4b1b8
platform: linux/amd64
paths:
- /usr/local/lib/erlang/erts-15.0/bin/beam.smp
- version: 9.3.8
images:
- ref: swipl:9.3.8@sha256:6a15e6a03afe943228924a5502ba763e653ff28d9b3391e2b3e1fc3e991f37d4
platform: linux/amd64
paths:
- /usr/lib/swipl/bin/x86_64-linux/swipl
- version: 1.21.3
images:
- ref: golang:1.21.3@sha256:3ce8313c3513515040870c55e0c041a2b94f3576a58cfd3948633604214aa811
@@ -285,6 +300,13 @@ from-images:
platform: linux/amd64
paths:
- /usr/bin/arangosh
- name: arangodb
version: 3.12.0-2
images:
- ref: arangodb:3.12.0.2@sha256:6ba2e4284cd0f4835e3ef034be90fb947c3d61225d65d07e3b2d2d893e47de25
platform: linux/amd64
paths:
- /usr/bin/arangosh
- version: 15.1
images:
- ref: postgres:15.1@sha256:b4140dd3a62f364f16a82c1bd88d28b9887ecb47f07dbe2941237d073574d428
@@ -433,6 +455,12 @@ from-images:
paths:
- /usr/local/bin/traefik
- version: 3.0.4
images:
- ref: traefik:3.0.4@sha256:12a7cc4232b5b7fe027673da8c096144525f59a8eabc87e52260aac0ec5a1219
platform: linux/riscv64
paths:
- /usr/local/bin/traefik
# from the original dynamic fixtures...
@@ -1,4 +1,5 @@
FROM --platform=linux/amd64 fedora:41 as build
FROM --platform=linux/amd64 fedora:41@sha256:c05bf79137835bf5c521c58f8252d6031780ae865a0379ab57f412e0ac6b42aa as build
FROM scratch
COPY --from=build /bin/sha256sum /sha256sum
+1 -5
View File
@@ -20,12 +20,8 @@ const (
// NewGoModuleFileCataloger returns a new cataloger object that searches within go.mod files.
func NewGoModuleFileCataloger(opts CatalogerConfig) pkg.Cataloger {
c := goModCataloger{
licenses: newGoLicenses(modFileCatalogerName, opts),
}
return generic.NewCataloger(modFileCatalogerName).
WithParserByGlobs(c.parseGoModFile, "**/go.mod")
WithParserByGlobs(newGoModCataloger(opts).parseGoModFile, "**/go.mod")
}
// NewGoModuleBinaryCataloger returns a new cataloger object that searches within binaries built by the go compiler.
+12 -12
View File
@@ -20,7 +20,7 @@ func Test_PackageCataloger_Binary(t *testing.T) {
name: "simple module with dependencies",
fixture: "image-small",
expectedPkgs: []string{
"anchore.io/not/real @ (devel) (/run-me)",
"anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/andybalholm/brotli @ v1.0.1 (/run-me)",
"github.com/dsnet/compress @ v0.0.2-0.20210315054119-f66993602bf5 (/run-me)",
"github.com/golang/snappy @ v0.0.2 (/run-me)",
@@ -34,17 +34,17 @@ func Test_PackageCataloger_Binary(t *testing.T) {
"stdlib @ go1.22.4 (/run-me)",
},
expectedRels: []string{
"github.com/andybalholm/brotli @ v1.0.1 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/dsnet/compress @ v0.0.2-0.20210315054119-f66993602bf5 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/golang/snappy @ v0.0.2 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/klauspost/compress @ v1.11.4 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/klauspost/pgzip @ v1.2.5 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/mholt/archiver/v3 @ v3.5.1 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/nwaples/rardecode @ v1.1.0 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/pierrec/lz4/v4 @ v4.1.2 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/ulikunitz/xz @ v0.5.9 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/xi2/xz @ v0.0.0-20171230120015-48954b6210f8 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"stdlib @ go1.22.4 (/run-me) [dependency-of] anchore.io/not/real @ (devel) (/run-me)",
"github.com/andybalholm/brotli @ v1.0.1 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/dsnet/compress @ v0.0.2-0.20210315054119-f66993602bf5 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/golang/snappy @ v0.0.2 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/klauspost/compress @ v1.11.4 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/klauspost/pgzip @ v1.2.5 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/mholt/archiver/v3 @ v3.5.1 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/nwaples/rardecode @ v1.1.0 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/pierrec/lz4/v4 @ v4.1.2 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/ulikunitz/xz @ v0.5.9 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"github.com/xi2/xz @ v0.0.0-20171230120015-48954b6210f8 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
"stdlib @ go1.22.4 (/run-me) [dependency-of] anchore.io/not/real @ v1.0.0 (/run-me)",
},
},
{
+17 -15
View File
@@ -41,6 +41,7 @@ type MainModuleVersionConfig struct {
func DefaultCatalogerConfig() CatalogerConfig {
g := CatalogerConfig{
MainModuleVersion: DefaultMainModuleVersionConfig(),
LocalModCacheDir: defaultGoModDir(),
}
// first process the proxy settings
@@ -67,24 +68,25 @@ func DefaultCatalogerConfig() CatalogerConfig {
}
}
if g.LocalModCacheDir == "" {
goPath := os.Getenv("GOPATH")
if goPath == "" {
homeDir, err := homedir.Dir()
if err != nil {
log.Debug("unable to determine user home dir: %v", err)
} else {
goPath = filepath.Join(homeDir, "go")
}
}
if goPath != "" {
g.LocalModCacheDir = filepath.Join(goPath, "pkg", "mod")
}
}
return g
}
// defaultGoModDir returns $GOPATH/pkg/mod or $HOME/go/pkg/mod based on environment variables available
func defaultGoModDir() string {
goPath := os.Getenv("GOPATH")
if goPath == "" {
homeDir, err := homedir.Dir()
if err != nil {
log.Warnf("unable to determine GOPATH or user home dir: %w", err)
return ""
}
goPath = filepath.Join(homeDir, "go")
}
return filepath.Join(goPath, "pkg", "mod")
}
func DefaultMainModuleVersionConfig() MainModuleVersionConfig {
return MainModuleVersionConfig{
FromLDFlags: true,
+2 -1
View File
@@ -1,6 +1,7 @@
package golang
import (
"path/filepath"
"testing"
"github.com/mitchellh/go-homedir"
@@ -47,7 +48,7 @@ func Test_Config(t *testing.T) {
opts: opts{},
expected: CatalogerConfig{
SearchLocalModCacheLicenses: false,
LocalModCacheDir: "/go/pkg/mod",
LocalModCacheDir: filepath.Join("/go", "pkg", "mod"),
SearchRemoteLicenses: false,
Proxies: []string{"https://my.proxy"},
NoProxy: []string{"my.private", "no.proxy"},
+216 -105
View File
@@ -21,25 +21,41 @@ import (
"github.com/scylladb/go-set/strset"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/cache"
"github.com/anchore/syft/internal/licenses"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/internal/fileresolver"
"github.com/anchore/syft/syft/license"
"github.com/anchore/syft/syft/pkg"
)
type goLicenses struct {
type goLicense struct {
Value string `json:"val,omitempty"`
SPDXExpression string `json:"spdx,omitempty"`
Type license.Type `json:"type,omitempty"`
URLs []string `json:"urls,omitempty"`
Locations []string `json:"locations,omitempty"`
}
type goLicenseResolver struct {
catalogerName string
opts CatalogerConfig
localModCacheResolver file.WritableResolver
localModCacheDir fs.FS
licenseCache cache.Resolver[[]goLicense]
lowerLicenseFileNames *strset.Set
}
func newGoLicenses(catalogerName string, opts CatalogerConfig) goLicenses {
return goLicenses{
func newGoLicenseResolver(catalogerName string, opts CatalogerConfig) goLicenseResolver {
var localModCacheDir fs.FS
if opts.SearchLocalModCacheLicenses {
localModCacheDir = os.DirFS(opts.LocalModCacheDir)
}
return goLicenseResolver{
catalogerName: catalogerName,
opts: opts,
localModCacheResolver: modCacheResolver(opts.LocalModCacheDir),
localModCacheDir: localModCacheDir,
licenseCache: cache.GetResolverCachingErrors[[]goLicense]("golang", "v1"),
lowerLicenseFileNames: strset.New(lowercaseLicenseFiles()...),
}
}
@@ -63,98 +79,103 @@ func remotesForModule(proxies []string, noProxy []string, module string) []strin
return proxies
}
func modCacheResolver(modCacheDir string) file.WritableResolver {
var r file.WritableResolver
func (c *goLicenseResolver) getLicenses(resolver file.Resolver, moduleName, moduleVersion string) ([]pkg.License, error) {
// search the scan target first, ignoring local and remote sources
goLicenses, err := c.findLicensesInSource(resolver,
fmt.Sprintf(`**/go/pkg/mod/%s@%s/*`, processCaps(moduleName), moduleVersion),
)
if err != nil || len(goLicenses) > 0 {
return toPkgLicenses(goLicenses), err
}
if modCacheDir == "" {
log.Trace("unable to determine mod cache directory, skipping mod cache resolver")
r = fileresolver.Empty{}
} else {
stat, err := os.Stat(modCacheDir)
if os.IsNotExist(err) || stat == nil || !stat.IsDir() {
log.Tracef("unable to open mod cache directory: %s, skipping mod cache resolver", modCacheDir)
r = fileresolver.Empty{}
} else {
r = fileresolver.NewFromUnindexedDirectory(modCacheDir)
// look in the local host mod directory...
if c.opts.SearchLocalModCacheLicenses {
goLicenses, err = c.getLicensesFromLocal(moduleName, moduleVersion)
if err != nil || len(goLicenses) > 0 {
return toPkgLicenses(goLicenses), err
}
}
return r
}
func (c *goLicenses) getLicenses(resolver file.Resolver, moduleName, moduleVersion string) (licenses []pkg.License, err error) {
licenses, err = c.findLicenses(resolver,
fmt.Sprintf(`**/go/pkg/mod/%s@%s/*`, processCaps(moduleName), moduleVersion),
)
if err != nil || len(licenses) > 0 {
return requireCollection(licenses), err
// download from remote sources
if c.opts.SearchRemoteLicenses {
goLicenses, err = c.getLicensesFromRemote(moduleName, moduleVersion)
}
// look in the local host mod cache...
licenses, err = c.getLicensesFromLocal(moduleName, moduleVersion)
if err != nil || len(licenses) > 0 {
return requireCollection(licenses), err
}
// we did not find it yet and remote searching was enabled
licenses, err = c.getLicensesFromRemote(moduleName, moduleVersion)
return requireCollection(licenses), err
return toPkgLicenses(goLicenses), err
}
func (c *goLicenses) getLicensesFromLocal(moduleName, moduleVersion string) ([]pkg.License, error) {
if !c.opts.SearchLocalModCacheLicenses {
func (c *goLicenseResolver) getLicensesFromLocal(moduleName, moduleVersion string) ([]goLicense, error) {
if c.localModCacheDir == nil {
return nil, nil
}
// if we're running against a directory on the filesystem, it may not include the
// user's homedir / GOPATH, so we defer to using the localModCacheResolver
return c.findLicenses(c.localModCacheResolver, moduleSearchGlob(moduleName, moduleVersion))
}
subdir := moduleDir(moduleName, moduleVersion)
func (c *goLicenses) getLicensesFromRemote(moduleName, moduleVersion string) ([]pkg.License, error) {
if !c.opts.SearchRemoteLicenses {
return nil, nil
}
proxies := remotesForModule(c.opts.Proxies, c.opts.NoProxy, moduleName)
fsys, err := getModule(proxies, moduleName, moduleVersion)
// get the local subdirectory containing the specific go module
dir, err := fs.Sub(c.localModCacheDir, subdir)
if err != nil {
return nil, err
}
dir := moduleDir(moduleName, moduleVersion)
// populate the mod cache with the results
err = fs.WalkDir(fsys, ".", func(filePath string, d fs.DirEntry, err error) error {
if err != nil {
log.Debug(err)
return nil
}
if d.IsDir() {
return nil
}
f, err := fsys.Open(filePath)
if err != nil {
return err
}
return c.localModCacheResolver.Write(file.NewLocation(path.Join(dir, filePath)), f)
})
if err != nil {
log.Tracef("remote proxy walk failed for: %s", moduleName)
}
return c.findLicenses(c.localModCacheResolver, moduleSearchGlob(moduleName, moduleVersion))
// if we're running against a directory on the filesystem, it may not include the
// user's homedir / GOPATH, so we defer to using the localModCacheResolver
// we use $GOPATH/pkg/mod to avoid leaking information about the user's system
return c.findLicensesInFS("file://$GOPATH/pkg/mod/"+subdir+"/", dir)
}
func (c *goLicenses) findLicenses(resolver file.Resolver, globMatch string) (out []pkg.License, err error) {
out = make([]pkg.License, 0)
if resolver == nil {
return
}
func (c *goLicenseResolver) getLicensesFromRemote(moduleName, moduleVersion string) ([]goLicense, error) {
return c.licenseCache.Resolve(fmt.Sprintf("%s/%s", moduleName, moduleVersion), func() ([]goLicense, error) {
proxies := remotesForModule(c.opts.Proxies, c.opts.NoProxy, moduleName)
urlPrefix, fsys, err := getModule(proxies, moduleName, moduleVersion)
if err != nil {
return nil, err
}
return c.findLicensesInFS(urlPrefix, fsys)
})
}
func (c *goLicenseResolver) findLicensesInFS(urlPrefix string, fsys fs.FS) ([]goLicense, error) {
var out []goLicense
err := fs.WalkDir(fsys, ".", func(filePath string, d fs.DirEntry, err error) error {
if err != nil {
log.Debugf("error reading %s#%s: %v", urlPrefix, filePath, err)
return err
}
if d == nil {
log.Debugf("nil entry for %s#%s", urlPrefix, filePath)
return nil
}
if !c.lowerLicenseFileNames.Has(strings.ToLower(d.Name())) {
return nil
}
rdr, err := fsys.Open(filePath)
if err != nil {
log.Debugf("error opening license file %s: %v", filePath, err)
return nil
}
defer internal.CloseAndLogError(rdr, filePath)
parsed, err := licenses.Parse(rdr, file.NewLocation(filePath))
if err != nil {
log.Debugf("error parsing license file %s: %v", filePath, err)
return nil
}
// since these licenses are found in an external fs.FS, not in the scanned source,
// get rid of the locations but keep information about the where the license was found
// by prepending the urlPrefix to the internal path for an accurate representation
for _, l := range toGoLicenses(parsed) {
l.URLs = []string{urlPrefix + filePath}
l.Locations = nil
out = append(out, l)
}
return nil
})
return out, err
}
func (c *goLicenseResolver) findLicensesInSource(resolver file.Resolver, globMatch string) ([]goLicense, error) {
var out []goLicense
locations, err := resolver.FilesByGlob(globMatch)
if err != nil {
return nil, err
@@ -168,11 +189,19 @@ func (c *goLicenses) findLicenses(resolver file.Resolver, globMatch string) (out
out = append(out, parsed...)
}
return
// if we have a directory but simply don't have any found license files, indicate this so we
// don't re-download modules continually
if len(locations) > 0 && len(out) == 0 {
return nil, noLicensesFound{
glob: globMatch,
}
}
return out, nil
}
func (c *goLicenses) parseLicenseFromLocation(l file.Location, resolver file.Resolver) ([]pkg.License, error) {
var out []pkg.License
func (c *goLicenseResolver) parseLicenseFromLocation(l file.Location, resolver file.Resolver) ([]goLicense, error) {
var out []goLicense
fileName := path.Base(l.RealPath)
if c.lowerLicenseFileNames.Has(strings.ToLower(fileName)) {
contents, err := resolver.FileContentsByLocation(l)
@@ -185,7 +214,7 @@ func (c *goLicenses) parseLicenseFromLocation(l file.Location, resolver file.Res
return nil, err
}
out = append(out, parsed...)
out = append(out, toGoLicenses(parsed)...)
}
return out, nil
}
@@ -194,13 +223,9 @@ func moduleDir(moduleName, moduleVersion string) string {
return fmt.Sprintf("%s@%s", processCaps(moduleName), moduleVersion)
}
func moduleSearchGlob(moduleName, moduleVersion string) string {
return fmt.Sprintf("%s/*", moduleDir(moduleName, moduleVersion))
}
func requireCollection(licenses []pkg.License) []pkg.License {
func requireCollection[T any](licenses []T) []T {
if licenses == nil {
return make([]pkg.License, 0)
return make([]T, 0)
}
return licenses
}
@@ -213,18 +238,19 @@ func processCaps(s string) string {
})
}
func getModule(proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
func getModule(proxies []string, moduleName, moduleVersion string) (urlPrefix string, fsys fs.FS, err error) {
for _, proxy := range proxies {
u, _ := url.Parse(proxy)
if proxy == "direct" {
fsys, err = getModuleRepository(moduleName, moduleVersion)
urlPrefix, fsys, err = getModuleRepository(moduleName, moduleVersion)
continue
}
switch u.Scheme {
case "https", "http":
fsys, err = getModuleProxy(proxy, moduleName, moduleVersion)
urlPrefix, fsys, err = getModuleProxy(proxy, moduleName, moduleVersion)
case "file":
p := filepath.Join(u.Path, moduleName, "@v", moduleVersion)
urlPrefix = path.Join("file://", p) + "/"
fsys = os.DirFS(p)
}
if fsys != nil {
@@ -234,13 +260,13 @@ func getModule(proxies []string, moduleName, moduleVersion string) (fsys fs.FS,
return
}
func getModuleProxy(proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
func getModuleProxy(proxy string, moduleName string, moduleVersion string) (moduleURL string, out fs.FS, _ error) {
u := fmt.Sprintf("%s/%s/@v/%s.zip", proxy, moduleName, moduleVersion)
// get the module zip
resp, err := http.Get(u) //nolint:gosec
if err != nil {
return nil, err
return "", nil, err
}
defer func() { _ = resp.Body.Close() }()
@@ -250,25 +276,25 @@ func getModuleProxy(proxy string, moduleName string, moduleVersion string) (out
// try lowercasing it; some packages have mixed casing that really messes up the proxy
resp, err = http.Get(u) //nolint:gosec
if err != nil {
return nil, err
return "", nil, err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to get module zip: %s", resp.Status)
return "", nil, fmt.Errorf("failed to get module zip: %s", resp.Status)
}
}
// read the zip
b, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
return "", nil, err
}
out, err = zip.NewReader(bytes.NewReader(b), resp.ContentLength)
versionPath := findVersionPath(out, ".")
out = getSubFS(out, versionPath)
return out, err
return u + "#" + versionPath + "/", out, err
}
func findVersionPath(f fs.FS, dir string) string {
@@ -288,26 +314,111 @@ func findVersionPath(f fs.FS, dir string) string {
return ""
}
func getModuleRepository(moduleName string, moduleVersion string) (fs.FS, error) {
func getModuleRepository(moduleName string, moduleVersion string) (string, fs.FS, error) {
repoName := moduleName
parts := strings.Split(moduleName, "/")
if len(parts) > 2 {
repoName = fmt.Sprintf("%s/%s/%s", parts[0], parts[1], parts[2])
}
// see if there's a hash and use that if so, otherwise use a tag
splitVersion := strings.Split(moduleVersion, "-")
var cloneRefName plumbing.ReferenceName
refPath := ""
if len(splitVersion) < 3 {
tagName := splitVersion[0]
cloneRefName = plumbing.NewTagReferenceName(tagName)
refPath = "/tags/" + tagName
}
f := memfs.New()
buf := &bytes.Buffer{}
_, err := git.Clone(memory.NewStorage(), f, &git.CloneOptions{
URL: fmt.Sprintf("https://%s", repoName),
ReferenceName: plumbing.NewTagReferenceName(moduleVersion), // FIXME version might be a SHA
repoURL := fmt.Sprintf("https://%s", repoName)
r, err := git.Clone(memory.NewStorage(), f, &git.CloneOptions{
URL: repoURL,
ReferenceName: cloneRefName,
SingleBranch: true,
Depth: 1,
Progress: buf,
})
if err != nil {
return nil, fmt.Errorf("%w -- %s", err, buf.String())
return "", nil, fmt.Errorf("%w -- %s", err, buf.String())
}
return billyFSAdapter{fs: f}, nil
if len(splitVersion) > 2 {
sha := splitVersion[len(splitVersion)-1]
hash, err := r.ResolveRevision(plumbing.Revision(sha))
if err != nil || hash == nil {
log.Tracef("unable to resolve hash %s: %v", sha, err)
} else {
w, err := r.Worktree()
if err != nil {
log.Tracef("unable to get worktree, using default: %v", err)
}
err = w.Checkout(&git.CheckoutOptions{
Hash: *hash,
})
if err != nil {
log.Tracef("unable to checkout commit, using default: %v", err)
} else {
refPath = "/refs/" + hash.String()
}
}
}
return repoURL + refPath + "/", billyFSAdapter{fs: f}, err
}
type noLicensesFound struct {
glob string
}
func (l noLicensesFound) Error() string {
return fmt.Sprintf("unable to find license information matching: %s", l.glob)
}
var _ error = (*noLicensesFound)(nil)
func toPkgLicenses(goLicenses []goLicense) []pkg.License {
var out []pkg.License
for _, l := range goLicenses {
out = append(out, pkg.License{
Value: l.Value,
SPDXExpression: l.SPDXExpression,
Type: l.Type,
URLs: l.URLs,
Locations: toPkgLocations(l.Locations),
})
}
return requireCollection(out)
}
func toPkgLocations(goLocations []string) file.LocationSet {
out := file.NewLocationSet()
for _, l := range goLocations {
out.Add(file.NewLocation(l))
}
return out
}
func toGoLicenses(pkgLicenses []pkg.License) []goLicense {
var out []goLicense
for _, l := range pkgLicenses {
out = append(out, goLicense{
Value: l.Value,
SPDXExpression: l.SPDXExpression,
Type: l.Type,
URLs: l.URLs,
Locations: toGoLocations(l.Locations),
})
}
return out
}
func toGoLocations(locations file.LocationSet) []string {
var out []string
for _, l := range locations.ToSlice() {
out = append(out, l.RealPath)
}
return out
}
+78 -14
View File
@@ -4,10 +4,12 @@ import (
"archive/zip"
"bytes"
"fmt"
"io/fs"
"net/http"
"net/http/httptest"
"os"
"path"
"path/filepath"
"strings"
"testing"
@@ -36,7 +38,8 @@ func Test_LocalLicenseSearch(t *testing.T) {
Value: "Apache-2.0",
SPDXExpression: "Apache-2.0",
Type: license.Concluded,
Locations: file.NewLocationSet(loc1),
URLs: []string{"file://$GOPATH/pkg/mod/" + loc1.RealPath},
Locations: file.NewLocationSet(),
},
},
{
@@ -46,7 +49,8 @@ func Test_LocalLicenseSearch(t *testing.T) {
Value: "MIT",
SPDXExpression: "MIT",
Type: license.Concluded,
Locations: file.NewLocationSet(loc2),
URLs: []string{"file://$GOPATH/pkg/mod/" + loc2.RealPath},
Locations: file.NewLocationSet(),
},
},
{
@@ -56,7 +60,8 @@ func Test_LocalLicenseSearch(t *testing.T) {
Value: "Apache-2.0",
SPDXExpression: "Apache-2.0",
Type: license.Concluded,
Locations: file.NewLocationSet(loc3),
URLs: []string{"file://$GOPATH/pkg/mod/" + loc3.RealPath},
Locations: file.NewLocationSet(),
},
},
}
@@ -66,11 +71,11 @@ func Test_LocalLicenseSearch(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
l := newGoLicenses(
l := newGoLicenseResolver(
"",
CatalogerConfig{
SearchLocalModCacheLicenses: true,
LocalModCacheDir: path.Join(wd, "test-fixtures", "licenses", "pkg", "mod"),
LocalModCacheDir: filepath.Join(wd, "test-fixtures", "licenses", "pkg", "mod"),
},
)
licenses, err := l.getLicenses(fileresolver.Empty{}, test.name, test.version)
@@ -97,7 +102,7 @@ func Test_RemoteProxyLicenseSearch(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
testDir := path.Join(wd, "test-fixtures", "licenses", "pkg", "mod", processCaps(modPath)+"@"+modVersion)
testDir := filepath.Join(wd, "test-fixtures", "licenses", "pkg", "mod", processCaps(modPath)+"@"+modVersion)
archive := zip.NewWriter(buf)
@@ -106,9 +111,9 @@ func Test_RemoteProxyLicenseSearch(t *testing.T) {
for _, f := range entries {
// the zip files downloaded contain a path to the repo that somewhat matches where it ends up on disk,
// so prefix entries with something similar
writer, err := archive.Create(path.Join("github.com/something/some@version", f.Name()))
writer, err := archive.Create(path.Join(moduleDir(modPath, modVersion), f.Name()))
require.NoError(t, err)
contents, err := os.ReadFile(path.Join(testDir, f.Name()))
contents, err := os.ReadFile(filepath.Join(testDir, f.Name()))
require.NoError(t, err)
_, err = writer.Write(contents)
require.NoError(t, err)
@@ -136,7 +141,8 @@ func Test_RemoteProxyLicenseSearch(t *testing.T) {
Value: "Apache-2.0",
SPDXExpression: "Apache-2.0",
Type: license.Concluded,
Locations: file.NewLocationSet(loc1),
URLs: []string{server.URL + "/github.com/someorg/somename/@v/v0.3.2.zip#" + loc1.RealPath},
Locations: file.NewLocationSet(),
},
},
{
@@ -146,21 +152,20 @@ func Test_RemoteProxyLicenseSearch(t *testing.T) {
Value: "MIT",
SPDXExpression: "MIT",
Type: license.Concluded,
Locations: file.NewLocationSet(loc2),
URLs: []string{server.URL + "/github.com/CapORG/CapProject/@v/v4.111.5.zip#" + loc2.RealPath},
Locations: file.NewLocationSet(),
},
},
}
modDir := path.Join(t.TempDir())
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
l := newGoLicenses(
l := newGoLicenseResolver(
"",
CatalogerConfig{
SearchRemoteLicenses: true,
Proxies: []string{server.URL},
LocalModCacheDir: modDir,
},
)
@@ -240,3 +245,62 @@ func Test_findVersionPath(t *testing.T) {
vp := findVersionPath(f, ".")
require.Equal(t, "github.com/someorg/somepkg@version", vp)
}
func Test_walkDirErrors(t *testing.T) {
resolver := newGoLicenseResolver("", CatalogerConfig{})
_, err := resolver.findLicensesInFS("somewhere", badFS{})
require.Error(t, err)
}
type badFS struct{}
func (b badFS) Open(_ string) (fs.File, error) {
return nil, fmt.Errorf("error")
}
var _ fs.FS = (*badFS)(nil)
func Test_noLocalGoModDir(t *testing.T) {
emptyTmp := t.TempDir()
validTmp := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(validTmp, "mod@ver"), 0700|os.ModeDir))
tests := []struct {
name string
dir string
wantErr require.ErrorAssertionFunc
}{
{
name: "empty",
dir: "",
wantErr: require.Error,
},
{
name: "invalid dir",
dir: filepath.Join(emptyTmp, "invalid-dir"),
wantErr: require.Error,
},
{
name: "missing mod dir",
dir: emptyTmp,
wantErr: require.Error,
},
{
name: "valid mod dir",
dir: validTmp,
wantErr: require.NoError,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
resolver := newGoLicenseResolver("", CatalogerConfig{
SearchLocalModCacheLicenses: true,
LocalModCacheDir: test.dir,
})
_, err := resolver.getLicensesFromLocal("mod", "ver")
test.wantErr(t, err)
})
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ func (c *goBinaryCataloger) newGoBinaryPackage(resolver file.Resolver, dep *debu
dep = dep.Replace
}
licenses, err := c.licenses.getLicenses(resolver, dep.Path, dep.Version)
licenses, err := c.licenseResolver.getLicenses(resolver, dep.Path, dep.Version)
if err != nil {
log.Tracef("error getting licenses for golang package: %s %v", dep.Path, err)
}
+63 -17
View File
@@ -11,6 +11,7 @@ import (
"io"
"regexp"
"runtime/debug"
"slices"
"strings"
"time"
@@ -38,21 +39,21 @@ var (
// inject the correct version into the main module of the build process
knownBuildFlagPatterns = []*regexp.Regexp{
regexp.MustCompile(`(?m)\.([gG]it)?([bB]uild)?[vV]er(sion)?=(\S+/)*(?P<version>v?\d+.\d+.\d+[-\w]*)`),
regexp.MustCompile(`(?m)\.([tT]ag)=(\S+/)*(?P<version>v?\d+.\d+.\d+[-\w]*)`),
regexp.MustCompile(`(?m)\.[a-zA-Z0-9]*([rR]elease)?([gG]it)?([bB]uild)?[vV]er(sion)?=(\S+/)*(?P<version>v?\d+.\d+.\d+[-\w]*)`),
regexp.MustCompile(`(?m)\.[a-zA-Z0-9]*([tT]ag)=(\S+/)*(?P<version>v?\d+.\d+.\d+[-\w]*)`),
}
)
const devel = "(devel)"
type goBinaryCataloger struct {
licenses goLicenses
licenseResolver goLicenseResolver
mainModuleVersion MainModuleVersionConfig
}
func newGoBinaryCataloger(opts CatalogerConfig) *goBinaryCataloger {
return &goBinaryCataloger{
licenses: newGoLicenses(binaryCatalogerName, opts),
licenseResolver: newGoLicenseResolver(binaryCatalogerName, opts),
mainModuleVersion: opts.MainModuleVersion,
}
}
@@ -97,17 +98,19 @@ func createModuleRelationships(main pkg.Package, deps []pkg.Package) []artifact.
return relationships
}
var emptyModule debug.Module
var moduleFromPartialPackageBuild = debug.Module{Path: "command-line-arguments"}
func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file.Location, mod *extendedBuildInfo, arch string, reader io.ReadSeekCloser) (*pkg.Package, []pkg.Package) {
var pkgs []pkg.Package
if mod == nil {
return nil, pkgs
return nil, nil
}
var empty debug.Module
if mod.Main == empty && mod.Path != "" {
mod.Main = createMainModuleFromPath(mod.Path)
if missingMainModule(mod) {
mod.Main = createMainModuleFromPath(mod)
}
var pkgs []pkg.Package
for _, dep := range mod.Deps {
if dep == nil {
continue
@@ -130,7 +133,7 @@ func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file
}
}
if mod.Main == empty {
if mod.Main == emptyModule {
return nil, pkgs
}
@@ -139,6 +142,16 @@ func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file
return &main, pkgs
}
func missingMainModule(mod *extendedBuildInfo) bool {
if mod.Main == emptyModule && mod.Path != "" {
return true
}
// special case: when invoking go build with a source file and not a package (directory) then you will
// see "command-line-arguments" as the main module path... even though that's not the main module. In this
// circumstance, we should treat the main module as missing and search for it within the dependencies.
return mod.Main == moduleFromPartialPackageBuild
}
func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *extendedBuildInfo, arch string, location file.Location, reader io.ReadSeekCloser) pkg.Package {
gbs := getBuildSettings(mod.Settings)
gover, experiments := getExperimentsFromVersion(mod.GoVersion)
@@ -167,6 +180,10 @@ func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *exten
version := c.findMainModuleVersion(metadata, gbs, reader)
if version != "" {
// make sure version is prefixed with v as some build systems parsed
// during `findMainModuleVersion` can include incomplete semver
// vx.x.x is correct
version = ensurePrefix(version, "v")
main.Version = version
main.PURL = packageURL(main.Name, main.Version)
@@ -195,7 +212,7 @@ func (c *goBinaryCataloger) findMainModuleVersion(metadata *pkg.GolangBinaryBuil
// version of the package.
ldflags, _ = metadata.BuildSettings.Get("-ldflags")
majorVersion, fullVersion = extractVersionFromLDFlags(ldflags)
majorVersion, fullVersion = extractVersionFromLDFlags(ldflags, metadata.MainModule)
if fullVersion != "" {
return fullVersion
}
@@ -245,13 +262,14 @@ func extractVersionFromContents(reader io.Reader) string {
return ""
}
func extractVersionFromLDFlags(ldflags string) (majorVersion string, fullVersion string) {
func extractVersionFromLDFlags(ldflags string, maimModule string) (majorVersion string, fullVersion string) {
if ldflags == "" {
return "", ""
}
for _, pattern := range knownBuildFlagPatterns {
groups := internal.MatchNamedCaptureGroups(pattern, ldflags)
newPattern := regexp.MustCompile(fmt.Sprintf(`(main|%s\/[^\s]*)%s`, strings.ReplaceAll(maimModule, "/", "\\/"), pattern.String()))
groups := internal.MatchNamedCaptureGroups(newPattern, ldflags)
v, ok := groups["version"]
if !ok {
@@ -358,8 +376,36 @@ func getExperimentsFromVersion(version string) (string, []string) {
return version, experiments
}
func createMainModuleFromPath(path string) (mod debug.Module) {
mod.Path = path
mod.Version = devel
return
func createMainModuleFromPath(existing *extendedBuildInfo) debug.Module {
// search for a main module candidate within the dependencies
var mainModuleCandidates []debug.Module
var usedIndex int
for i, dep := range existing.Deps {
if dep == nil {
continue
}
if dep.Version == devel {
usedIndex = i
mainModuleCandidates = append(mainModuleCandidates, *dep)
}
}
if len(mainModuleCandidates) == 1 {
// we need to prune the dependency from module list
existing.Deps = slices.Delete(existing.Deps, usedIndex, usedIndex+1)
return mainModuleCandidates[0]
}
// otherwise craft a main module from the path (a bit of a cop out, but allows us to have a main module)
return debug.Module{
Path: existing.Path,
Version: devel,
}
}
func ensurePrefix(s, prefix string) string {
if !strings.HasPrefix(s, prefix) {
return prefix + s
}
return s
}
+148 -12
View File
@@ -210,7 +210,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
},
{
name: "buildGoPkgInfo parses a blank mod and returns no packages",
mod: &extendedBuildInfo{&debug.BuildInfo{}, nil, ""},
mod: &extendedBuildInfo{BuildInfo: &debug.BuildInfo{}, cryptoSettings: nil, arch: ""},
expected: []pkg.Package(nil),
},
{
@@ -946,6 +946,95 @@ func TestBuildGoPkgInfo(t *testing.T) {
},
}},
},
{
name: "parse a mod from path (partial build of package)",
mod: &extendedBuildInfo{
BuildInfo: &debug.BuildInfo{
GoVersion: "go1.22.2",
Main: debug.Module{Path: "command-line-arguments"},
Settings: []debug.BuildSetting{
{
Key: "-ldflags",
Value: `build -ldflags="-w -s -X github.com/kuskoman/logstash-exporter/config.Version=v1.7.0 -X github.com/kuskoman/logstash-exporter/config.GitCommit=db696dbcfe5a91d288d5ad44ce8ccbea97e65978 -X github.com/kuskoman/logstash-exporter/config.BuildDate=2024-07-17T08:12:17Z"`,
},
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
},
Deps: []*debug.Module{
{
Path: "github.com/kuskoman/something-else",
Version: "v1.2.3",
},
{
Path: "github.com/kuskoman/logstash-exporter",
Version: "(devel)",
},
},
},
arch: archDetails,
},
expected: []pkg.Package{
{
Name: "github.com/kuskoman/something-else",
Language: pkg.Go,
Type: pkg.GoModulePkg,
Version: "v1.2.3",
PURL: "pkg:golang/github.com/kuskoman/something-else@v1.2.3",
Locations: file.NewLocationSet(
file.NewLocationFromCoordinates(
file.Coordinates{
RealPath: "/a-path",
FileSystemID: "layer-id",
},
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
),
Metadata: pkg.GolangBinaryBuildinfoEntry{
GoCompiledVersion: "go1.22.2",
Architecture: archDetails,
MainModule: "github.com/kuskoman/logstash-exporter", // correctly attached the main module
},
},
{
Name: "github.com/kuskoman/logstash-exporter",
Language: pkg.Go,
Type: pkg.GoModulePkg,
Version: "v1.7.0",
PURL: "pkg:golang/github.com/kuskoman/logstash-exporter@v1.7.0",
Locations: file.NewLocationSet(
file.NewLocationFromCoordinates(
file.Coordinates{
RealPath: "/a-path",
FileSystemID: "layer-id",
},
).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
),
Metadata: pkg.GolangBinaryBuildinfoEntry{
GoCompiledVersion: "go1.22.2",
BuildSettings: []pkg.KeyValue{
{
Key: "-ldflags",
Value: `build -ldflags="-w -s -X github.com/kuskoman/logstash-exporter/config.Version=v1.7.0 -X github.com/kuskoman/logstash-exporter/config.GitCommit=db696dbcfe5a91d288d5ad44ce8ccbea97e65978 -X github.com/kuskoman/logstash-exporter/config.BuildDate=2024-07-17T08:12:17Z"`,
},
{
Key: "GOARCH",
Value: "amd64",
},
{
Key: "GOOS",
Value: "darwin",
},
{
Key: "GOAMD64",
Value: "v1",
},
},
Architecture: archDetails,
MainModule: "github.com/kuskoman/logstash-exporter",
},
},
},
},
}
for _, test := range tests {
@@ -979,6 +1068,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
func Test_extractVersionFromLDFlags(t *testing.T) {
tests := []struct {
name string
mainModule string
ldflags string
wantMajorVersion string
wantFullVersion string
@@ -989,12 +1079,14 @@ func Test_extractVersionFromLDFlags(t *testing.T) {
},
{
name: "syft ldflags",
mainModule: "github.com/anchore/syft",
ldflags: ` build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0 -X github.com/anchore/syft/internal/version.gitCommit=b2b332e8b2b66af0905e98b54ebd713a922be1a8 -X github.com/anchore/syft/internal/version.buildDate=2023-04-21T16:20:25Z -X github.com/anchore/syft/internal/version.gitDescription=v0.79.0 "`,
wantMajorVersion: "0",
wantFullVersion: "v0.79.0",
},
{
name: "kubectl ldflags",
name: "kubectl ldflags",
mainModule: "k8s.io/kubernetes/vendor/k8s.io/client-go",
ldflags: ` build -asmflags=all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes
build -compiler=gc
build -gcflags="all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes "
@@ -1004,24 +1096,28 @@ func Test_extractVersionFromLDFlags(t *testing.T) {
},
{
name: "nerdctl ldflags",
mainModule: "github.com/containerd/nerdctl",
ldflags: ` build -ldflags="-s -w -X github.com/containerd/nerdctl/pkg/version.Version=v1.3.1 -X github.com/containerd/nerdctl/pkg/version.Revision=b224b280ff3086516763c7335fc0e0997aca617a"`,
wantMajorVersion: "1",
wantFullVersion: "v1.3.1",
},
{
name: "limactl ldflags",
mainModule: "github.com/lima-vm/lima",
ldflags: ` build -ldflags="-s -w -X github.com/lima-vm/lima/pkg/version.Version=v0.15.1"`,
wantMajorVersion: "0",
wantFullVersion: "v0.15.1",
},
{
name: "terraform ldflags",
mainModule: "github.com/hashicorp/terraform",
ldflags: ` build -ldflags="-w -s -X 'github.com/hashicorp/terraform/version.Version=1.4.6' -X 'github.com/hashicorp/terraform/version.Prerelease='"`,
wantMajorVersion: "1",
wantFullVersion: "v1.4.6",
},
{
name: "kube-apiserver ldflags",
name: "kube-apiserver ldflags",
mainModule: "k8s.io/kubernetes/vendor/k8s.io/client-go",
ldflags: ` build -asmflags=all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes
build -buildmode=exe
build -compiler=gc
@@ -1031,14 +1127,16 @@ func Test_extractVersionFromLDFlags(t *testing.T) {
wantFullVersion: "v1.27.1",
},
{
name: "prometheus ldflags",
name: "prometheus ldflags",
mainModule: "github.com/prometheus/common",
ldflags: ` build -ldflags="-X github.com/prometheus/common/version.Version=2.44.0 -X github.com/prometheus/common/version.Revision=1ac5131f698ebc60f13fe2727f89b115a41f6558 -X github.com/prometheus/common/version.Branch=HEAD -X github.com/prometheus/common/version.BuildUser=root@739e8181c5db -X github.com/prometheus/common/version.BuildDate=20230514-06:18:11 -extldflags '-static'"
build -tags=netgo,builtinassets,stringlabels`,
wantMajorVersion: "2",
wantFullVersion: "v2.44.0",
},
{
name: "influxdb ldflags",
name: "influxdb ldflags",
mainModule: "github.com/influxdata/influxdb-client-go/v2",
ldflags: ` build -ldflags="-s -w -X main.version=v2.7.1 -X main.commit=407fa622e9 -X main.date=2023-04-28T13:24:27Z -linkmode=external -extld=/musl/x86_64/bin/musl-gcc -extldflags '-fno-PIC -static-pie -Wl,-z,stack-size=8388608'"
build -tags=assets,sqlite_foreign_keys,sqlite_json,static_build,noasm`,
wantMajorVersion: "2",
@@ -1046,68 +1144,106 @@ func Test_extractVersionFromLDFlags(t *testing.T) {
},
{
name: "gitea ldflags",
mainModule: "code.gitea.io/gitea",
ldflags: ` build -ldflags=" -X \"main.MakeVersion=GNU Make 4.1\" -X \"main.Version=1.19.3\" -X \"main.Tags=bindata sqlite sqlite_unlock_notify\" "`,
wantMajorVersion: "1",
wantFullVersion: "v1.19.3",
},
{
name: "docker sbom cli ldflags",
mainModule: "github.com/docker/sbom-cli-plugin",
ldflags: ` build -ldflags="-w -s -extldflags '-static' -X github.com/docker/sbom-cli-plugin/internal/version.version=0.6.1-SNAPSHOT-02cf1c8 -X github.com/docker/sbom-cli-plugin/internal/version.gitCommit=02cf1c888ad6662109ac6e3be618392514a56316 -X github.com/docker/sbom-cli-plugin/internal/version.gitDescription=v0.6.1-dirty "`,
wantMajorVersion: "0",
wantFullVersion: "v0.6.1-SNAPSHOT-02cf1c8",
},
{
name: "docker scout ldflags",
mainModule: "github.com/docker/scout-cli-plugin",
ldflags: ` build -ldflags="-w -s -extldflags '-static' -X github.com/docker/scout-cli-plugin/internal.version=0.10.0 "`,
wantMajorVersion: "0",
wantFullVersion: "v0.10.0",
},
{
name: "influx telegraf ldflags",
mainModule: "github.com/influxdata/telegraf",
ldflags: ` build -ldflags="-w -s -X github.com/influxdata/telegraf/internal.Commit=a3a884a1 -X github.com/influxdata/telegraf/internal.Branch=HEAD -X github.com/influxdata/telegraf/internal.Version=1.26.2"`,
wantMajorVersion: "1",
wantFullVersion: "v1.26.2",
},
{
name: "argocd ldflags",
mainModule: "github.com/argoproj/argo-cd/v2",
ldflags: ` build -ldflags="-X github.com/argoproj/argo-cd/v2/common.version=2.7.2 -X github.com/argoproj/argo-cd/v2/common.buildDate=2023-05-12T14:06:49Z -X github.com/argoproj/argo-cd/v2/common.gitCommit=cbee7e6011407ed2d1066c482db74e97e0cc6bdb -X github.com/argoproj/argo-cd/v2/common.gitTreeState=clean -X github.com/argoproj/argo-cd/v2/common.kubectlVersion=v0.24.2 -extldflags=\"-static\""`,
wantMajorVersion: "2",
wantFullVersion: "v2.7.2",
},
{
name: "kustomize ldflags",
mainModule: "sigs.k8s.io/kustomize/api",
ldflags: ` build -ldflags="-s -X sigs.k8s.io/kustomize/api/provenance.version=kustomize/v4.5.7 -X sigs.k8s.io/kustomize/api/provenance.gitCommit=56d82a8378dfc8dc3b3b1085e5a6e67b82966bd7 -X sigs.k8s.io/kustomize/api/provenance.buildDate=2022-08-02T16:35:54Z "`,
wantMajorVersion: "4",
wantFullVersion: "v4.5.7",
},
{
name: "TiDB 7.5.0 ldflags",
mainModule: "github.com/pingcap/tidb",
ldflags: `build -ldflags="-X \"github.com/pingcap/tidb/pkg/parser/mysql.TiDBReleaseVersion=v7.5.0\" -X \"github.com/pingcap/tidb/pkg/util/versioninfo.TiDBBuildTS=2023-11-24 08:51:04\" -X \"github.com/pingcap/tidb/pkg/util/versioninfo.TiDBGitHash=069631e2ecfedc000ffb92c67207bea81380f020\" -X \"github.com/pingcap/tidb/pkg/util/versioninfo.TiDBGitBranch=heads/refs/tags/v7.5.0\" -X \"github.com/pingcap/tidb/pkg/util/versioninfo.TiDBEdition=Community\" "`,
wantMajorVersion: "7",
wantFullVersion: "v7.5.0",
},
{
name: "TiDB 6.1.7 ldflags",
mainModule: "github.com/pingcap/tidb",
ldflags: `build -ldflags="-X \"github.com/pingcap/tidb/parser/mysql.TiDBReleaseVersion=v6.1.7\" -X \"github.com/pingcap/tidb/util/versioninfo.TiDBBuildTS=2023-07-04 12:06:03\" -X \"github.com/pingcap/tidb/util/versioninfo.TiDBGitHash=613ecc5f731b2843e1d53a43915e2cd8da795936\" -X \"github.com/pingcap/tidb/util/versioninfo.TiDBGitBranch=heads/refs/tags/v6.1.7\" -X \"github.com/pingcap/tidb/util/versioninfo.TiDBEdition=Community\" "`,
wantMajorVersion: "6",
wantFullVersion: "v6.1.7",
},
{
name: "logstash-exporter",
ldflags: `build -ldflags="-w -s -X github.com/kuskoman/logstash-exporter/config.Version=v1.7.0 -X github.com/kuskoman/logstash-exporter/config.GitCommit=db696dbcfe5a91d288d5ad44ce8ccbea97e65978 -X github.com/kuskoman/logstash-exporter/config.BuildDate=2024-07-17T08:12:17Z"`,
wantMajorVersion: "1",
wantFullVersion: "v1.7.0",
},
//////////////////////////////////////////////////////////////////
// negative cases
{
name: "hugo ldflags",
ldflags: ` build -ldflags="-s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio"`,
name: "hugo ldflags",
mainModule: "github.com/gohugoio/hugo",
ldflags: ` build -ldflags="-s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio"`,
},
{
name: "ghostunnel ldflags",
ldflags: ` build -ldflags="-X main.version=77d9aaa"`,
name: "ghostunnel ldflags",
mainModule: "github.com/ghostunnel/ghostunnel",
ldflags: ` build -ldflags="-X main.version=77d9aaa"`,
},
{
name: "opa ldflags",
ldflags: `build -ldflags=" -X github.com/open-policy-agent/opa/version.Hostname=9549178459bc"`,
name: "opa ldflags",
mainModule: "github.com/open-policy-agent/opa",
ldflags: `build -ldflags=" -X github.com/open-policy-agent/opa/version.Hostname=9549178459bc"`,
},
///////////////////////////////////////////////////////////////////
// trickier cases
{
name: "macvlan plugin for cri-o ldflags",
mainModule: "github.com/containernetworking/plugins",
ldflags: ` build -ldflags="-extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=v1.2.0"`,
wantMajorVersion: "1",
wantFullVersion: "v1.2.0",
},
{
name: "coder ldflags",
mainModule: "github.com/coder/coder",
ldflags: ` build -ldflags="-s -w -X 'github.com/coder/coder/buildinfo.tag=0.23.4'"`,
wantMajorVersion: "0",
wantFullVersion: "v0.23.4",
},
{
name: "hypothetical multiple versions in ldflags",
mainModule: "github.com/foo/baz",
ldflags: ` build -ldflags="-extldflags -static -X github.com/foo/bar/buildversion.BuildVersion=v1.2.0 -X github.com/foo/baz/buildversion.BuildVersion=v2.4.5"`,
wantMajorVersion: "2",
wantFullVersion: "v2.4.5",
},
///////////////////////////////////////////////////////////////////
// don't know how to handle these... yet
//{
@@ -1127,7 +1263,7 @@ func Test_extractVersionFromLDFlags(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotMajorVersion, gotFullVersion := extractVersionFromLDFlags(tt.ldflags)
gotMajorVersion, gotFullVersion := extractVersionFromLDFlags(tt.ldflags, tt.mainModule)
assert.Equal(t, tt.wantMajorVersion, gotMajorVersion, "unexpected major version")
assert.Equal(t, tt.wantFullVersion, gotFullVersion, "unexpected full version")
})
+9 -3
View File
@@ -19,7 +19,13 @@ import (
)
type goModCataloger struct {
licenses goLicenses
licenseResolver goLicenseResolver
}
func newGoModCataloger(opts CatalogerConfig) *goModCataloger {
return &goModCataloger{
licenseResolver: newGoLicenseResolver(modFileCatalogerName, opts),
}
}
// parseGoModFile takes a go.mod and lists all packages discovered.
@@ -44,7 +50,7 @@ func (c *goModCataloger) parseGoModFile(_ context.Context, resolver file.Resolve
}
for _, m := range f.Require {
licenses, err := c.licenses.getLicenses(resolver, m.Mod.Path, m.Mod.Version)
licenses, err := c.licenseResolver.getLicenses(resolver, m.Mod.Path, m.Mod.Version)
if err != nil {
log.Tracef("error getting licenses for package: %s %v", m.Mod.Path, err)
}
@@ -65,7 +71,7 @@ func (c *goModCataloger) parseGoModFile(_ context.Context, resolver file.Resolve
// remove any old packages and replace with new ones...
for _, m := range f.Replace {
licenses, err := c.licenses.getLicenses(resolver, m.New.Path, m.New.Version)
licenses, err := c.licenseResolver.getLicenses(resolver, m.New.Path, m.New.Version)
if err != nil {
log.Tracef("error getting licenses for package: %s %v", m.New.Path, err)
}
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/internal/fileresolver"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
)
@@ -91,10 +92,11 @@ func TestParseGoMod(t *testing.T) {
for _, test := range tests {
t.Run(test.fixture, func(t *testing.T) {
c := goModCataloger{}
c := newGoModCataloger(DefaultCatalogerConfig())
pkgtest.NewCatalogTester().
FromFile(t, test.fixture).
Expects(test.expected, nil).
WithResolver(fileresolver.Empty{}).
TestParser(t, c.parseGoModFile)
})
}

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