Compare commits

...
109 Commits
Author SHA1 Message Date
dependabot[bot] 49736e7c4a chore(deps): bump golang.org/x/net from 0.42.0 to 0.43.0 (#4122)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.42.0 to 0.43.0.
- [Commits](https://github.com/golang/net/compare/v0.42.0...v0.43.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.43.0
  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>
2025-08-08 17:51:06 +00:00
dependabot[bot] 7a9e1e06da chore(deps): bump golang.org/x/mod from 0.26.0 to 0.27.0 (#4123)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/mod/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.27.0
  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>
2025-08-08 13:35:44 -04:00
dependabot[bot] 7b92913a00 chore(deps): bump github/codeql-action from 3.29.7 to 3.29.8 (#4124)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.7 to 3.29.8.
- [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/51f77329afa6477de8c49fc9c7046c15b9a4e79d...76621b61decf072c1cee8dd1ce2d2a82d33c17ed)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.8
  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>
2025-08-08 13:35:35 -04:00
Will MurphyandKeith Zantow 594b309cdf feat: add binary classifier for hashicorp vault (#4121)
* add binary classifier for hashicorp vault

The Go Binary Cataloger isn't able to parse the version out of the
binary shipped in the DockerHub images of hashicorp/vault because the
version of the main module isn't set in the binary. Therefore, add a
binary classifier cataloger for this binary.

Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>

* chore: add test fixtures, update vault

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

* chore: set binary classifier package type based on PURL

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

* chore: use github.com/hashicorp/vault as package name

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

* chore: update tests

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

---------

Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2025-08-08 13:26:15 -04:00
Keith Zantow 8c6a2bcbb6 fix: nondeterministic Java archive cataloging and improve groupID (#4118)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-08-07 10:55:10 -04:00
dependabot[bot] d4d311155f chore(deps): bump docker/login-action from 3.4.0 to 3.5.0 (#4115)
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/74a5d142397b4f367a81961eba4e8cd7edddf772...184bdaa0721073962dff0199f1fb9940f07167d1)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.5.0
  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>
2025-08-07 10:48:53 -04:00
dependabot[bot] 118f564cf3 chore(deps): bump actions/cache from 4.2.3 to 4.2.4 (#4119)
Bumps [actions/cache](https://github.com/actions/cache) from 4.2.3 to 4.2.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/5a3ec84eff668545956fd18022155c47e93e2684...0400d5f644dc74513175e3cd8d07132dd4860809)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 4.2.4
  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>
2025-08-07 10:47:40 -04:00
dependabot[bot] b59c902996 chore(deps): bump actions/cache in /.github/actions/bootstrap (#4120)
Bumps [actions/cache](https://github.com/actions/cache) from 4.2.3 to 4.2.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/5a3ec84eff668545956fd18022155c47e93e2684...0400d5f644dc74513175e3cd8d07132dd4860809)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 4.2.4
  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>
2025-08-07 10:47:25 -04:00
anchore-actions-token-generator[bot]andspiffcs fad9340051 chore(deps): update tools to latest versions (#4111)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-08-04 11:20:26 -04:00
anchore-actions-token-generator[bot]andwagoodman 3820cba0cd chore(deps): update CPE dictionary index (#4112)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-08-04 11:20:09 -04:00
anchore-actions-token-generator[bot]andspiffcs 5af72b6663 chore(deps): update tools to latest versions (#4108)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-31 12:04:54 -04:00
dependabot[bot] 801b21bb37 chore(deps): bump github/codeql-action from 3.29.4 to 3.29.5 (#4096)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.4 to 3.29.5.
- [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/4e828ff8d448a8a6e532957b1811f387a63867e8...51f77329afa6477de8c49fc9c7046c15b9a4e79d)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.5
  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>
2025-07-30 14:29:07 -04:00
anchore-actions-token-generator[bot]andwagoodman 386ef842d9 chore(deps): update anchore dependencies (#4104)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-07-30 17:41:35 +00:00
bd79463e77 chore(deps): update anchore dependencies (#4098)
* chore(deps): update anchore dependencies

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

* address reader close operations

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

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-07-30 17:23:07 +00:00
Alex Goodman 8a7302c5cf migrate to get.anchore.io (#4095)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-07-30 10:54:22 -04:00
dependabot[bot] 28ba092375 chore(deps): bump github.com/anchore/stereoscope (#4091)
Bumps [github.com/anchore/stereoscope](https://github.com/anchore/stereoscope) from 0.1.7-0.20250716200927-94c6f92877d4 to 0.1.7.
- [Release notes](https://github.com/anchore/stereoscope/releases)
- [Changelog](https://github.com/anchore/stereoscope/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/stereoscope/commits/v0.1.7)

---
updated-dependencies:
- dependency-name: github.com/anchore/stereoscope
  dependency-version: 0.1.7
  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>
2025-07-30 09:12:55 -04:00
dependabot[bot] fa68af468d chore(deps): bump github.com/docker/docker (#4092)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.2.2+incompatible to 28.3.3+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.2.2...v28.3.3)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.3+incompatible
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-29 16:29:03 -04:00
dependabot[bot] 700a777356 chore(deps): bump modernc.org/sqlite from 1.38.1 to 1.38.2 (#4088)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.38.1 to 1.38.2.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.38.1...v1.38.2)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.38.2
  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>
2025-07-29 10:29:57 -04:00
dependabot[bot] 71aa59a210 chore(deps): bump github.com/gkampitakis/go-snaps from 0.5.13 to 0.5.14 (#4089)
Bumps [github.com/gkampitakis/go-snaps](https://github.com/gkampitakis/go-snaps) from 0.5.13 to 0.5.14.
- [Release notes](https://github.com/gkampitakis/go-snaps/releases)
- [Commits](https://github.com/gkampitakis/go-snaps/compare/v0.5.13...v0.5.14)

---
updated-dependencies:
- dependency-name: github.com/gkampitakis/go-snaps
  dependency-version: 0.5.14
  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>
2025-07-29 10:29:45 -04:00
dependabot[bot] d0d9c6a8e5 chore(deps): bump github.com/bmatcuk/doublestar/v4 from 4.9.0 to 4.9.1 (#4087) 2025-07-28 13:39:36 -04:00
dependabot[bot] 702b4358e9 chore(deps): bump github.com/olekukonko/tablewriter from 1.0.8 to 1.0.9 (#4086) 2025-07-28 13:39:22 -04:00
dependabot[bot] 4a69c00c23 chore(deps): bump github.com/jedib0t/go-pretty/v6 from 6.6.7 to 6.6.8 (#4085) 2025-07-28 13:39:06 -04:00
dependabot[bot] 998742f38e chore(deps): bump modernc.org/sqlite from 1.38.0 to 1.38.1 (#4084) 2025-07-28 17:38:42 +00:00
anchore-actions-token-generator[bot]andspiffcs bb8ea024e1 chore(deps): update tools to latest versions (#4082)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-28 12:01:09 -04:00
anchore-actions-token-generator[bot]andwagoodman 3f28480b3d chore(deps): update CPE dictionary index (#4083)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-07-28 10:51:16 -04:00
anchore-actions-token-generator[bot]andspiffcs 5465bf4227 chore(deps): update tools to latest versions (#4079)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-24 15:18:12 -04:00
dependabot[bot] 8b2c4a134e chore(deps): bump github/codeql-action from 3.29.3 to 3.29.4 (#4080)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.3 to 3.29.4.
- [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/d6bbdef45e766d081b84a2def353b0055f728d3e...4e828ff8d448a8a6e532957b1811f387a63867e8)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.4
  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>
2025-07-24 15:17:49 -04:00
anchore-actions-token-generator[bot] d7046099e9 chore(deps): update tools to latest versions (#4076) 2025-07-23 21:03:20 -04:00
Alex Goodman f0a990b85f chore: add source completion tester (#4077)
* add source completion tester

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

* add missing t.Helper calls

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

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-07-23 13:49:47 +00:00
Keith Zantow 48bf81cf7f fix: align binary java detection with jvm cataloger + support IBM (#4046)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-07-22 12:06:32 -04:00
anchore-actions-token-generator[bot]andspiffcs 78c7cd2cc2 chore(deps): update tools to latest versions (#4072)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-22 09:49:58 -04:00
dependabot[bot] a192787d44 chore(deps): bump github/codeql-action from 3.29.2 to 3.29.3 (#4074)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.2 to 3.29.3.
- [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/181d5eefc20863364f96762470ba6f862bdef56b...d6bbdef45e766d081b84a2def353b0055f728d3e)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.3
  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>
2025-07-22 09:49:43 -04:00
dependabot[bot] d5a562c368 chore(deps): bump anchore/sbom-action from 0.20.2 to 0.20.4 (#4073)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.20.2 to 0.20.4.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/cee1b8e05ae5b2593a75e197229729eabaa9f8ec...7b36ad622f042cab6f59a75c2ac24ccb256e9b45)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.4
  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>
2025-07-22 09:49:40 -04:00
Christopher Angelo Phillips 6f36b586ba chore: update release workflow to persist credentials for git tag step (#4069)
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2025-07-21 19:23:14 +00:00
anchore-actions-token-generator[bot]andspiffcs a620baff90 chore(deps): update anchore dependencies (#4068)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-21 14:12:47 -04:00
dependabot[bot] 5b14d160cf chore(deps): bump pygments (#4064)
Bumps [pygments](https://github.com/pygments/pygments) from 1.6 to 2.15.0.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/1.6...2.15.0)

---
updated-dependencies:
- dependency-name: pygments
  dependency-version: 2.15.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-21 13:07:27 -04:00
anchore-actions-token-generator[bot]andspiffcs 0a9567e88c chore(deps): update tools to latest versions (#4065)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-21 13:07:18 -04:00
dependabot[bot] af787d685c chore(deps): bump sigstore/cosign-installer from 3.9.1 to 3.9.2 (#4066)
Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.9.1 to 3.9.2.
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](https://github.com/sigstore/cosign-installer/compare/398d4b0eeef1380460a10c8013a76f728fb906ac...d58896d6a1865668819e1d91763c7751a165e159)

---
updated-dependencies:
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.9.2
  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>
2025-07-21 13:06:59 -04:00
anchore-actions-token-generator[bot]andwagoodman 64b62c086c chore(deps): update CPE dictionary index (#4067)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-07-21 07:57:39 -04:00
c491dab35b feat: add parsing for uv.lock (#3763)
* feat: add parsing for uv.lock (#3268)

Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* Still no tests, but much more complete

Next up: start writing tests! :)

Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* chore: finish out functionality and write tests

Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* Merge the .NET deps.json and PE binary catalogers (#3563)

* add combined deps.json + pe binary cataloger

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

* deprecate pe and deps standalone catalogers

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

* parse resource names + add tests

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

* fix integration and CLI tests

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

* add some helpful code comments

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

* allow for dropping Dep packages that are missing DLLs

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

* migrate json schema changes to 24

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

* keep application configuration

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

* correct config help

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

* [wip] detect claims of dlls within deps.json

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

* [wip] fix tests

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

* add assembly repack detection

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

* .net package count is lower due to dll claim requirement

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

---------

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

* better .NET cpe generation (#3764)

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

* Better represent .NET runtime packages (#3768)

* clean up .NET runtime packages

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

* add runtime relationships

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

* remove runtime references from binary package name

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

---------

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

* chore(deps): update CPE dictionary index (#3769)

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* chore(deps): bump modernc.org/sqlite from 1.36.1 to 1.37.0 (#3771)

Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.36.1 to 1.37.0.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.36.1...v1.37.0)

---
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>
Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* chore(deps): bump 8398a7/action-slack from 3.16.2 to 3.18.0 (#3767)

Bumps [8398a7/action-slack](https://github.com/8398a7/action-slack) from 3.16.2 to 3.18.0.
- [Release notes](https://github.com/8398a7/action-slack/releases)
- [Commits](https://github.com/8398a7/action-slack/compare/28ba43ae48961b90635b50953d216767a6bea486...1750b5085f3ec60384090fb7c52965ef822e869e)

---
updated-dependencies:
- dependency-name: 8398a7/action-slack
  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>
Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* chore(deps): bump golang.org/x/net from 0.37.0 to 0.38.0 (#3766)

Bumps [golang.org/x/net](https://github.com/golang/net) from 0.37.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.37.0...v0.38.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>
Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* chore: move/modify code for lint issues

Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* chore: make sure private structs are not exported

Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* fix tests

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

* generate json schema

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

* chore: update readme to include uv

Signed-off-by: Joshua Kugler <tek30584@adobe.com>

* chore: use uv as the package manager name

Signed-off-by: Joshua Kugler <tek30584@adobe.com>

---------

Signed-off-by: Joshua Kugler <tek30584@adobe.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: anchore-actions-token-generator[bot] <102182147+anchore-actions-token-generator[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-17 18:26:56 +00:00
dependabot[bot] 0e5db45aad chore(deps): bump marocchino/sticky-pull-request-comment (#4063)
Bumps [marocchino/sticky-pull-request-comment](https://github.com/marocchino/sticky-pull-request-comment) from 2.9.3 to 2.9.4.
- [Release notes](https://github.com/marocchino/sticky-pull-request-comment/releases)
- [Commits](https://github.com/marocchino/sticky-pull-request-comment/compare/d2ad0de260ae8b0235ce059e63f2949ba9e05943...773744901bac0e8cbb5a0dc842800d45e9b2b405)

---
updated-dependencies:
- dependency-name: marocchino/sticky-pull-request-comment
  dependency-version: 2.9.4
  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>
2025-07-17 09:27:02 -04:00
Will Murphy 9cda2de2ad chore: lint gh actions with zizmor (#4062)
Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>
2025-07-16 17:12:38 -04:00
anchore-actions-token-generator[bot]andspiffcs 37c182d5be chore(deps): update tools to latest versions (#4060)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-15 11:32:27 -04:00
dependabot[bot] cef2a38117 chore(deps): bump github.com/go-viper/mapstructure/v2 (#4061)
Bumps [github.com/go-viper/mapstructure/v2](https://github.com/go-viper/mapstructure) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/go-viper/mapstructure/releases)
- [Changelog](https://github.com/go-viper/mapstructure/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-viper/mapstructure/compare/v2.3.0...v2.4.0)

---
updated-dependencies:
- dependency-name: github.com/go-viper/mapstructure/v2
  dependency-version: 2.4.0
  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>
2025-07-15 11:32:11 -04:00
dependabot[bot] 75eda3976d chore(deps): bump github.com/bmatcuk/doublestar/v4 from 4.8.1 to 4.9.0 (#4059)
Bumps [github.com/bmatcuk/doublestar/v4](https://github.com/bmatcuk/doublestar) from 4.8.1 to 4.9.0.
- [Release notes](https://github.com/bmatcuk/doublestar/releases)
- [Commits](https://github.com/bmatcuk/doublestar/compare/v4.8.1...v4.9.0)

---
updated-dependencies:
- dependency-name: github.com/bmatcuk/doublestar/v4
  dependency-version: 4.9.0
  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>
2025-07-14 17:14:11 +00:00
dependabot[bot] 2b1710b009 chore(deps): bump golang.org/x/mod from 0.25.0 to 0.26.0 (#4054)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.25.0 to 0.26.0.
- [Commits](https://github.com/golang/mod/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.26.0
  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>
2025-07-14 14:43:04 +00:00
mikey strauss 9caad26ee5 Pkg Metadata type unmarshal bug (#4043)
Signed-off-by: houdini91 <mdstrauss91@gmail.com>
2025-07-14 10:28:38 -04:00
anchore-actions-token-generator[bot]andspiffcs d88ad07855 chore(deps): update tools to latest versions (#4053)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-07-14 10:27:40 -04:00
dependabot[bot] 13986b7cea chore(deps): bump golang.org/x/net from 0.41.0 to 0.42.0 (#4056)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.41.0 to 0.42.0.
- [Commits](https://github.com/golang/net/compare/v0.41.0...v0.42.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.42.0
  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>
2025-07-14 10:27:10 -04:00
anchore-actions-token-generator[bot]andwagoodman 75db6527bc chore(deps): update CPE dictionary index (#4058)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-07-14 10:27:01 -04:00
dependabot[bot] 1c0ed133a3 chore(deps): bump github.com/olekukonko/tablewriter from 1.0.7 to 1.0.8 (#4049)
Bumps [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) from 1.0.7 to 1.0.8.
- [Commits](https://github.com/olekukonko/tablewriter/compare/v1.0.7...v1.0.8)

---
updated-dependencies:
- dependency-name: github.com/olekukonko/tablewriter
  dependency-version: 1.0.8
  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>
2025-07-08 15:27:02 -04:00
anchore-actions-token-generator[bot]andwagoodman 9928386d38 chore(deps): update CPE dictionary index (#4050)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-07-08 15:26:50 -04:00
dependabot[bot] 9dd06981b4 chore(deps): bump github.com/hashicorp/hcl/v2 from 2.23.0 to 2.24.0 (#4051)
Bumps [github.com/hashicorp/hcl/v2](https://github.com/hashicorp/hcl) from 2.23.0 to 2.24.0.
- [Release notes](https://github.com/hashicorp/hcl/releases)
- [Changelog](https://github.com/hashicorp/hcl/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/hcl/compare/v2.23.0...v2.24.0)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/hcl/v2
  dependency-version: 2.24.0
  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>
2025-07-08 15:26:34 -04:00
dependabot[bot] f88be457ef chore(deps): bump github.com/charmbracelet/bubbletea from 1.3.5 to 1.3.6 (#4052)
Bumps [github.com/charmbracelet/bubbletea](https://github.com/charmbracelet/bubbletea) from 1.3.5 to 1.3.6.
- [Release notes](https://github.com/charmbracelet/bubbletea/releases)
- [Changelog](https://github.com/charmbracelet/bubbletea/blob/main/.goreleaser.yml)
- [Commits](https://github.com/charmbracelet/bubbletea/compare/v1.3.5...v1.3.6)

---
updated-dependencies:
- dependency-name: github.com/charmbracelet/bubbletea
  dependency-version: 1.3.6
  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>
2025-07-08 15:26:26 -04:00
Keith ZantowandAlex Goodman 02703d5c80 feat: RHEL EUS detection (#4023)
* feat: rhel eus detection

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

* chore: update tests

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

* chore: update more tests

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

* rename feature detection functions

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

---------

Signed-off-by: Keith Zantow <kzantow@gmail.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-07-07 14:11:20 +00:00
dependabot[bot] 9cbd52bdd7 chore(deps): bump anchore/sbom-action from 0.20.1 to 0.20.2 (#4048)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.20.1 to 0.20.2.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/9246b90769f852b3a8921f330c59e0b3f439d6e9...cee1b8e05ae5b2593a75e197229729eabaa9f8ec)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.2
  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>
2025-07-03 15:00:51 -04:00
anchore-actions-token-generator[bot]andwagoodman e8b62ab9ac chore(deps): update anchore dependencies (#4047)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-07-02 16:09:46 +00:00
anchore-actions-token-generator[bot]andwagoodman 2af1bca83f chore(deps): update anchore dependencies (#4045)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-07-02 11:50:29 -04:00
Carlos Tadeu Panato JuniorandAlex Goodman 2111d4d0e4 chore: upgrade tablewriter dependency to use new API (#3990)
* upgrade tablewriter

Signed-off-by: Carlos Panato <ctadeu@gmail.com>

* remove header line whitespace

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

* fix static analysis

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

---------

Signed-off-by: Carlos Panato <ctadeu@gmail.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-07-01 16:16:16 -04:00
dependabot[bot]andAlex Goodman 179cc70a36 chore(deps): bump github.com/Masterminds/semver/v3 from 3.3.1 to 3.4.0 (#4040)
* chore(deps): bump github.com/Masterminds/semver/v3 from 3.3.1 to 3.4.0

Bumps [github.com/Masterminds/semver/v3](https://github.com/Masterminds/semver) from 3.3.1 to 3.4.0.
- [Release notes](https://github.com/Masterminds/semver/releases)
- [Changelog](https://github.com/Masterminds/semver/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Masterminds/semver/compare/v3.3.1...v3.4.0)

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

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

* update error message expectations

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-07-01 19:21:02 +00:00
Christopher Angelo Phillips 1e3d2a2927 chore: update tests to read from latest test-fixture-cache and fix cache publish (#4042)
* feat: update integration test with correct package for httpd

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

* chore: update integration and cli tests with new upstream expectations

- php interpreter 8.3.21 => 8.3.22
- runCycloneDXInDocker update for local arm64 qemu emulation CycloneDX
- getSyftBinaryLocationByOS update to detect arm64 v8.0 artifact path

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

* chore: add snalshot to test command for fixture builds

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

* chore: update cdx in docker for all GOOS

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

---------

Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2025-07-01 14:11:36 +00:00
dependabot[bot] 421afac532 chore(deps): bump github.com/mholt/archives from 0.1.2 to 0.1.3 (#4032)
Bumps [github.com/mholt/archives](https://github.com/mholt/archives) from 0.1.2 to 0.1.3.
- [Release notes](https://github.com/mholt/archives/releases)
- [Commits](https://github.com/mholt/archives/compare/v0.1.2...v0.1.3)

---
updated-dependencies:
- dependency-name: github.com/mholt/archives
  dependency-version: 0.1.3
  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>
2025-06-30 17:58:41 -04:00
dependabot[bot] b0b10acb40 chore(deps): bump marocchino/sticky-pull-request-comment (#4019)
Bumps [marocchino/sticky-pull-request-comment](https://github.com/marocchino/sticky-pull-request-comment) from 2.9.2 to 2.9.3.
- [Release notes](https://github.com/marocchino/sticky-pull-request-comment/releases)
- [Commits](https://github.com/marocchino/sticky-pull-request-comment/compare/67d0dec7b07ed060a405f9b2a64b8ab319fdd7db...d2ad0de260ae8b0235ce059e63f2949ba9e05943)

---
updated-dependencies:
- dependency-name: marocchino/sticky-pull-request-comment
  dependency-version: 2.9.3
  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>
2025-06-30 17:58:32 -04:00
dependabot[bot] b90028bd1f chore(deps): bump sigstore/cosign-installer from 3.9.0 to 3.9.1 (#4022)
Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.9.0 to 3.9.1.
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](https://github.com/sigstore/cosign-installer/compare/v3.9.0...v3.9.1)

---
updated-dependencies:
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.9.1
  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>
2025-06-30 17:58:23 -04:00
anchore-actions-token-generator[bot]andspiffcs b5a1b309ca chore(deps): update tools to latest versions (#4035)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-06-30 17:17:49 -04:00
anchore-actions-token-generator[bot]andwagoodman 841f963e70 chore(deps): update CPE dictionary index (#4037)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-06-30 17:17:34 -04:00
dependabot[bot] ba59f57bfe chore(deps): bump github/codeql-action from 3.29.0 to 3.29.2 (#4039)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.0 to 3.29.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/ce28f5bb42b7a9f2c824e633a3f6ee835bab6858...181d5eefc20863364f96762470ba6f862bdef56b)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.2
  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>
2025-06-30 17:17:20 -04:00
Alex Goodman 2bda086423 Add ability to scan snaps (as a source) (#3929) 2025-06-25 16:53:35 -04:00
anchore-actions-token-generator[bot]andwagoodman 4eb8ba4575 chore(deps): update CPE dictionary index (#4021)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-06-23 11:30:19 -04:00
anchore-actions-token-generator[bot]andspiffcs 49115355d4 chore(deps): update tools to latest versions (#4016)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-06-19 14:02:03 -04:00
anchore-actions-token-generator[bot]andspiffcs d9eb1d7c1b chore(deps): update tools to latest versions (#4012)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-06-17 11:35:22 -04:00
dependabot[bot] 32a30f76c6 chore(deps): bump github.com/go-viper/mapstructure/v2 (#4014)
Bumps [github.com/go-viper/mapstructure/v2](https://github.com/go-viper/mapstructure) from 2.2.1 to 2.3.0.
- [Release notes](https://github.com/go-viper/mapstructure/releases)
- [Changelog](https://github.com/go-viper/mapstructure/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-viper/mapstructure/compare/v2.2.1...v2.3.0)

---
updated-dependencies:
- dependency-name: github.com/go-viper/mapstructure/v2
  dependency-version: 2.3.0
  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>
2025-06-17 11:35:09 -04:00
dependabot[bot] b52b13c03c chore(deps): bump sigstore/cosign-installer from 3.8.2 to 3.9.0 (#4015)
Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.8.2 to 3.9.0.
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](https://github.com/sigstore/cosign-installer/compare/v3.8.2...v3.9.0)

---
updated-dependencies:
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.9.0
  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>
2025-06-17 11:34:58 -04:00
anchore-actions-token-generator[bot]andwagoodman 0bfda2c514 chore(deps): update CPE dictionary index (#4007)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-06-16 11:15:50 -04:00
dependabot[bot] 0b57d03958 chore(deps): bump anchore/sbom-action from 0.20.0 to 0.20.1 (#4008)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.20.0 to 0.20.1.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/e11c554f704a0b820cbf8c51673f6945e0731532...9246b90769f852b3a8921f330c59e0b3f439d6e9)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.1
  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>
2025-06-16 11:15:37 -04:00
dependabot[bot] 72f9c42562 chore(deps): bump github.com/google/go-containerregistry (#4009)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.20.5 to 0.20.6.
- [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.5...v0.20.6)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  dependency-version: 0.20.6
  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>
2025-06-16 11:15:22 -04:00
anchore-actions-token-generator[bot]andspiffcs 181e180284 chore(deps): update tools to latest versions (#3992)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-06-13 10:38:44 -04:00
dependabot[bot] c19558dd73 chore(deps): bump github/codeql-action from 3.28.19 to 3.29.0 (#4000)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.19 to 3.29.0.
- [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/fca7ace96b7d713c7035871441bd52efbe39e27e...ce28f5bb42b7a9f2c824e633a3f6ee835bab6858)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.0
  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>
2025-06-12 10:37:53 -04:00
Keith Zantow 10f0631710 fix: provide separate nonroot image (#3998)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-06-11 17:00:55 -04:00
Alex Goodman 96c34ffc43 account for non-import shapes (#3997)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-06-11 13:11:40 -04:00
Alex Goodman 79b6d5daa4 Allow decoding of anchorectl json files (#3973)
* allow decoding of import sbom file shape

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

* address formatting

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

* add file mode and type processing

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

* use type to interpret the raw value

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

* safe mode convert should use uint32

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

* simpler decoder type

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

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-06-10 15:03:50 -04:00
dependabot[bot] cfa7cc5be9 chore(deps): bump github.com/anchore/stereoscope (#3991)
Bumps [github.com/anchore/stereoscope](https://github.com/anchore/stereoscope) from 0.1.5-0.20250604132324-344e29f37f05 to 0.1.5.
- [Release notes](https://github.com/anchore/stereoscope/releases)
- [Changelog](https://github.com/anchore/stereoscope/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/stereoscope/commits/v0.1.5)

---
updated-dependencies:
- dependency-name: github.com/anchore/stereoscope
  dependency-version: 0.1.5
  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>
2025-06-10 11:47:40 -04:00
Alex Goodman 18f9b5ab58 remove benchmark utils (#3982)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-06-09 18:24:49 +00:00
Keith Zantow 9090c69708 fix: exclude packages with SPDX GENERATED_FROM source package indication (#3981)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-06-09 14:12:23 -04:00
dependabot[bot] 1396a14550 chore(deps): bump modernc.org/sqlite from 1.37.1 to 1.38.0 (#3979)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.37.1 to 1.38.0.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.37.1...v1.38.0)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.38.0
  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>
2025-06-09 10:31:10 -04:00
dependabot[bot] 592bc0af7d chore(deps): bump github.com/go-git/go-git/v5 from 5.16.1 to 5.16.2 (#3978)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.16.1 to 5.16.2.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.16.1...v5.16.2)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-version: 5.16.2
  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>
2025-06-09 10:26:47 -04:00
anchore-actions-token-generator[bot]andspiffcs b6b8a8f52e chore(deps): update tools to latest versions (#3977)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-06-09 08:56:36 -04:00
anchore-actions-token-generator[bot]andwagoodman a196cc9215 chore(deps): update CPE dictionary index (#3976)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-06-09 08:56:18 -04:00
dependabot[bot] 12c8003317 chore(deps): bump golang.org/x/net from 0.40.0 to 0.41.0 (#3970)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.40.0 to 0.41.0.
- [Commits](https://github.com/golang/net/compare/v0.40.0...v0.41.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.41.0
  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>
2025-06-06 10:23:02 -04:00
dependabot[bot] 0a25c0ec5c chore(deps): bump github.com/sergi/go-diff (#3971)
Bumps [github.com/sergi/go-diff](https://github.com/sergi/go-diff) from 1.3.2-0.20230802210424-5b0b94c5c0d3 to 1.4.0.
- [Commits](https://github.com/sergi/go-diff/commits/v1.4.0)

---
updated-dependencies:
- dependency-name: github.com/sergi/go-diff
  dependency-version: 1.4.0
  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>
2025-06-06 10:22:54 -04:00
Christoph Blessing 5ae11bd1f7 Fix Python package dependency detection (#3965)
Previously a dependency relationship between two Python packages was not
detected if there were no parentheses around the version specifier in
the wheel metadata of the parent package. This commit allows detection
of such relationships.

Signed-off-by: Christoph Blessing <chris24.blessing@gmail.com>
2025-06-06 09:46:16 -04:00
John Vandenberg bc1cbde4f7 fix: Remove three Rust crate false positive CPE matches (#3967)
Signed-off-by: John Vandenberg <jayvdb@gmail.com>
2025-06-06 04:29:06 -04:00
Michael BrileyandAlex Goodman 868a6a7584 Harden Container Runtime with Non-Root User (#3941)
* Update Dockerfile

Signed-off-by: Michael Briley <michael.briley937@gmail.com>

* Update Dockerfile

Signed-off-by: Michael Briley <michael.briley937@gmail.com>

* Update validations.yaml

Signed-off-by: Michael Briley <michael.briley937@gmail.com>

* Update validations.yaml

Signed-off-by: Michael Briley <michael.briley937@gmail.com>

* Update Dockerfile

Signed-off-by: Michael Briley <michael.briley937@gmail.com>

* Update validations.yaml

Signed-off-by: Michael Briley <michael.briley937@gmail.com>

* Update Dockerfile

Signed-off-by: Michael Briley <michael.briley937@gmail.com>

* Update .goreleaser.yaml

Signed-off-by: Michael Briley <michael.briley937@gmail.com>

* Update .goreleaser.yaml

Signed-off-by: Michael Briley <michael.briley937@gmail.com>

* use distroless/static-debian12:nonroot directly

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

* keep manual manifest curation

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

* remove qemu usage

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

* add smoke test for snapshot

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

* split up manifests section with comments

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

* correct ci step name

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

* fix arch condition

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

* keep path prefix

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

---------

Signed-off-by: Michael Briley <michael.briley937@gmail.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-06-05 12:36:23 -04:00
John Vandenberg bd894b9c4d fix: Remove two Rust crate false positive CPE matches (#3962)
Rust crates opentelemetry and redis are being given CPEs that
match CVEs such as CVE-2023-45142 and CVE-2022-24735 respectively.
The vendor overrides added here prevent that.

Signed-off-by: John Vandenberg <jayvdb@gmail.com>
2025-06-05 10:28:54 -04:00
dependabot[bot] c36c69779a chore(deps): bump golang.org/x/mod from 0.24.0 to 0.25.0 (#3963)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.24.0 to 0.25.0.
- [Commits](https://github.com/golang/mod/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.25.0
  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>
2025-06-05 13:46:58 +00:00
dependabot[bot] cd23ccc6e6 chore(deps): bump github.com/gkampitakis/go-snaps from 0.5.12 to 0.5.13 (#3964)
Bumps [github.com/gkampitakis/go-snaps](https://github.com/gkampitakis/go-snaps) from 0.5.12 to 0.5.13.
- [Release notes](https://github.com/gkampitakis/go-snaps/releases)
- [Commits](https://github.com/gkampitakis/go-snaps/compare/v0.5.12...v0.5.13)

---
updated-dependencies:
- dependency-name: github.com/gkampitakis/go-snaps
  dependency-version: 0.5.13
  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>
2025-06-05 13:45:40 +00:00
Keith Zantow 71d84603c1 fix: bump stereoscope to fix symlink performance issue (#3953)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-06-04 15:50:03 +00:00
dependabot[bot] f2118b568d chore(deps): bump github.com/go-git/go-git/v5 from 5.16.0 to 5.16.1 (#3960)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.16.0 to 5.16.1.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.16.0...v5.16.1)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-version: 5.16.1
  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>
2025-06-04 14:02:45 +00:00
dependabot[bot] bb50f1650d chore(deps): bump github/codeql-action from 3.28.18 to 3.28.19 (#3952)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.18 to 3.28.19.
- [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/ff0a06e83cb2de871e5a09832bc6a81e7276941f...fca7ace96b7d713c7035871441bd52efbe39e27e)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.28.19
  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>
2025-06-03 10:20:24 -04:00
Christopher Angelo Phillips a0be514184 feat: add syft schema version to version command (#3949)
---------
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2025-06-02 15:50:21 +00:00
dependabot[bot] 8cc808f8f6 chore(deps): bump github.com/gkampitakis/go-snaps from 0.5.11 to 0.5.12 (#3943)
Bumps [github.com/gkampitakis/go-snaps](https://github.com/gkampitakis/go-snaps) from 0.5.11 to 0.5.12.
- [Release notes](https://github.com/gkampitakis/go-snaps/releases)
- [Commits](https://github.com/gkampitakis/go-snaps/compare/v0.5.11...v0.5.12)

---
updated-dependencies:
- dependency-name: github.com/gkampitakis/go-snaps
  dependency-version: 0.5.12
  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>
2025-06-02 10:46:30 -04:00
anchore-actions-token-generator[bot]andspiffcs 967e2f85bf chore(deps): update tools to latest versions (#3945)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2025-06-02 10:46:20 -04:00
anchore-actions-token-generator[bot]andwagoodman 339fea9851 chore(deps): update CPE dictionary index (#3947)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-06-02 10:43:31 -04:00
Keith Zantow 576e729c84 fix: revert incorrect graalvm unknown behavior (#3944)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-05-30 11:36:57 -04:00
dependabot[bot] b3e8926025 chore(deps): bump github.com/google/go-containerregistry (#3933)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.20.4 to 0.20.5.
- [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.4...v0.20.5)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  dependency-version: 0.20.5
  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>
2025-05-28 12:45:51 -04:00
anchore-actions-token-generator[bot]andwagoodman 002ec4510a chore(deps): update CPE dictionary index (#3935)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2025-05-28 12:45:42 -04:00
Thomas Gosteli 684e1e963d fix(terraform): parse provider lock entries without constraints (#3934)
In a .terraform.lock.hcl file in a provider block the `constraints` attribute is actually not required (=optional).

Signed-off-by: Thomas Gosteli <thomas.gosteli@protonmail.ch>
2025-05-27 14:55:19 -04:00
Dan LuhringandKeith Zantow bbf3bb5856 fix(relationship): favor real paths over symlinks for ownership by file (#3923)
Signed-off-by: Dan Luhring <dluhring@chainguard.dev>
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2025-05-23 14:33:19 -04:00
dependabot[bot] 31c1be6d4d chore(deps): bump modernc.org/sqlite from 1.37.0 to 1.37.1 (#3926)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.37.0 to 1.37.1.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.37.0...v1.37.1)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-version: 1.37.1
  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>
2025-05-22 10:47:26 -04:00
191 changed files with 16697 additions and 940 deletions
+7 -20
View File
@@ -26,7 +26,7 @@ tools:
# used for linting
- name: golangci-lint
version:
want: v2.1.6
want: v2.3.1
method: github-release
with:
repo: golangci/golangci-lint
@@ -34,7 +34,7 @@ tools:
# used for showing the changelog at release
- name: glow
version:
want: v2.1.0
want: v2.1.1
method: github-release
with:
repo: charmbracelet/glow
@@ -42,7 +42,7 @@ tools:
# used for signing the checksums file at release
- name: cosign
version:
want: v2.5.0
want: v2.5.3
method: github-release
with:
repo: sigstore/cosign
@@ -58,7 +58,7 @@ tools:
# used to release all artifacts
- name: goreleaser
version:
want: v2.9.0
want: v2.11.2
method: github-release
with:
repo: goreleaser/goreleaser
@@ -87,23 +87,10 @@ tools:
with:
repo: wagoodman/go-bouncer
# used for showing benchmark testing
- name: benchstat
version:
want: latest
method: go-proxy
with:
module: golang.org/x/perf
allow-unresolved-version: true
method: go-install
with:
entrypoint: cmd/benchstat
module: golang.org/x/perf
# used for running all local and CI tasks
- name: task
version:
want: v3.43.3
want: v3.44.1
method: github-release
with:
repo: go-task/task
@@ -111,7 +98,7 @@ tools:
# used for triggering a release
- name: gh
version:
want: v2.73.0
want: v2.76.2
method: github-release
with:
repo: cli/cli
@@ -127,7 +114,7 @@ tools:
# used to upload test fixture cache
- name: yq
version:
want: v4.45.4
want: v4.47.1
method: github-release
with:
repo: mikefarah/yq
+6 -3
View File
@@ -37,7 +37,7 @@ runs:
- name: Restore tool cache
if: inputs.tools == 'true'
id: tool-cache
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ${{ github.workspace }}/.tool
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('.binny.yaml') }}
@@ -55,12 +55,15 @@ runs:
- name: Install apt packages
if: inputs.bootstrap-apt-packages != ''
shell: bash
env:
APT_PACKAGES: ${{ inputs.bootstrap-apt-packages }}
run: |
DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y ${{ inputs.bootstrap-apt-packages }}
IFS=' ' read -ra packages <<< "$APT_PACKAGES"
DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y "${packages[@]}"
- name: Restore ORAS cache from github actions
if: inputs.download-test-fixture-cache == 'true'
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ${{ github.workspace }}/.tmp/oras-cache
key: ${{ inputs.cache-key-prefix }}-oras-cache
-22
View File
@@ -1,22 +0,0 @@
#!/usr/bin/env bash
set -ue
BIN="syft"
VERSION_FILE="VERSION"
VERSION=$1
# the source of truth as to whether we want to notify users of an update is if the release just created is NOT
# flagged as a pre-release on github
if [[ "$(curl -SsL https://api.github.com/repos/anchore/${BIN}/releases/tags/${VERSION} | jq .prerelease)" == "true" ]] ; then
echo "skipping publishing a version file (this is a pre-release: ${VERSION})"
exit 0
fi
echo "creating and publishing version file (${VERSION})"
# create a version file for version-update checks
echo "${VERSION}" | tee "${VERSION_FILE}"
# upload the version file that supports the application version update check
export AWS_DEFAULT_REGION=us-west-2
aws s3 cp "${VERSION_FILE}" s3://toolbox-data.anchore.io/${BIN}/releases/latest/VERSION
+5 -3
View File
@@ -37,6 +37,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Install Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 #v5.5.0
@@ -45,7 +47,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f #v3.28.18
uses: github/codeql-action/init@76621b61decf072c1cee8dd1ce2d2a82d33c17ed #v3.29.5
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -56,7 +58,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@ff0a06e83cb2de871e5a09832bc6a81e7276941f #v3.28.18
uses: github/codeql-action/autobuild@76621b61decf072c1cee8dd1ce2d2a82d33c17ed #v3.29.5
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -70,4 +72,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f #v3.28.18
uses: github/codeql-action/analyze@76621b61decf072c1cee8dd1ce2d2a82d33c17ed #v3.29.5
+8 -2
View File
@@ -28,9 +28,15 @@ jobs:
label:
name: "Label changes"
runs-on: ubuntu-22.04
permissions:
contents: read
pull-requests: write
issues: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- run: python .github/scripts/labeler.py
env:
@@ -40,7 +46,7 @@ jobs:
- name: Delete existing comment
if: ${{ hashFiles( env.CI_COMMENT_FILE ) == '' }}
uses: marocchino/sticky-pull-request-comment@67d0dec7b07ed060a405f9b2a64b8ab319fdd7db #v2.9.2
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 #v2.9.4
with:
header: ${{ env.COMMENT_HEADER }}
hide: true
@@ -48,7 +54,7 @@ jobs:
- name: Add comment
if: ${{ hashFiles( env.CI_COMMENT_FILE ) != '' }}
uses: marocchino/sticky-pull-request-comment@67d0dec7b07ed060a405f9b2a64b8ab319fdd7db #v2.9.2
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 #v2.9.4
with:
header: ${{ env.COMMENT_HEADER }}
path: ${{ env.CI_COMMENT_FILE }}
@@ -1,31 +0,0 @@
name: "Release: version file"
on:
workflow_dispatch:
inputs:
version:
description: release version to update the version file with (prefixed with v)
required: true
workflow_call:
inputs:
version:
type: string
description: release version to update the version file with (prefixed with v)
required: true
jobs:
release:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
- name: Update version file
run: make ci-release-version-file
env:
RELEASE_VERSION: ${{ github.event.inputs.version }}
# for updating the VERSION file in S3...
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
+37 -16
View File
@@ -16,6 +16,8 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Check if running on main
if: github.ref != 'refs/heads/main'
@@ -28,8 +30,10 @@ jobs:
- name: Check if tag already exists
# note: this will fail if the tag already exists
run: |
[[ "${{ github.event.inputs.version }}" == v* ]] || (echo "version '${{ github.event.inputs.version }}' does not have a 'v' prefix" && exit 1)
git tag ${{ github.event.inputs.version }}
[[ "$VERSION" == v* ]] || (echo "version '$VERSION' does not have a 'v' prefix" && exit 1)
git tag "$VERSION"
env:
VERSION: ${{ github.event.inputs.version }}
- name: Check static analysis results
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
@@ -87,13 +91,20 @@ jobs:
- name: Quality gate
if: steps.static-analysis.outputs.conclusion != 'success' || steps.unit.outputs.conclusion != 'success' || steps.integration.outputs.conclusion != 'success' || steps.cli-linux.outputs.conclusion != 'success' || steps.acceptance-linux.outputs.conclusion != 'success' || steps.acceptance-mac.outputs.conclusion != 'success'
env:
STATIC_ANALYSIS_STATUS: ${{ steps.static-analysis.conclusion }}
UNIT_TEST_STATUS: ${{ steps.unit.outputs.conclusion }}
INTEGRATION_TEST_STATUS: ${{ steps.integration.outputs.conclusion }}
ACCEPTANCE_LINUX_STATUS: ${{ steps.acceptance-linux.outputs.conclusion }}
ACCEPTANCE_MAC_STATUS: ${{ steps.acceptance-mac.outputs.conclusion }}
CLI_LINUX_STATUS: ${{ steps.cli-linux.outputs.conclusion }}
run: |
echo "Static Analysis Status: ${{ steps.static-analysis.conclusion }}"
echo "Unit Test Status: ${{ steps.unit.outputs.conclusion }}"
echo "Integration Test Status: ${{ steps.integration.outputs.conclusion }}"
echo "Acceptance Test (Linux) Status: ${{ steps.acceptance-linux.outputs.conclusion }}"
echo "Acceptance Test (Mac) Status: ${{ steps.acceptance-mac.outputs.conclusion }}"
echo "CLI Test (Linux) Status: ${{ steps.cli-linux.outputs.conclusion }}"
echo "Static Analysis Status: $STATIC_ANALYSIS_STATUS"
echo "Unit Test Status: $UNIT_TEST_STATUS"
echo "Integration Test Status: $INTEGRATION_TEST_STATUS"
echo "Acceptance Test (Linux) Status: $ACCEPTANCE_LINUX_STATUS"
echo "Acceptance Test (Mac) Status: $ACCEPTANCE_MAC_STATUS"
echo "CLI Test (Linux) Status: $CLI_LINUX_STATUS"
false
release:
@@ -108,18 +119,19 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
fetch-depth: 0
persist-credentials: true
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
- name: Login to Docker Hub
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 #v3.4.0
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 #v3.5.0
with:
username: ${{ secrets.ANCHOREOSSWRITE_DH_USERNAME }}
password: ${{ secrets.ANCHOREOSSWRITE_DH_PAT }}
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 #v3.4.0
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 #v3.5.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -129,10 +141,11 @@ jobs:
run: |
git config --global user.name "anchoreci"
git config --global user.email "anchoreci@users.noreply.github.com"
git tag -a ${{ github.event.inputs.version }} -m "Release ${{ github.event.inputs.version }}"
git tag -a "$VERSION" -m "Release $VERSION"
git push origin --tags
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ github.event.inputs.version }}
- name: Build & publish release artifacts
run: make ci-release
@@ -148,7 +161,7 @@ jobs:
# for updating brew formula in anchore/homebrew-syft
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
- uses: anchore/sbom-action@e11c554f704a0b820cbf8c51673f6945e0731532 #v0.20.0
- uses: anchore/sbom-action@7b36ad622f042cab6f59a75c2ac24ccb256e9b45 #v0.20.4
continue-on-error: true
with:
file: go.mod
@@ -164,9 +177,17 @@ jobs:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
if: ${{ success() }}
release-version-file:
release-install-script:
needs: [release]
uses: ./.github/workflows/release-version-file.yaml
if: ${{ needs.release.result == 'success' }}
uses: "anchore/workflows/.github/workflows/release-install-script.yaml@main"
with:
version: ${{ github.event.inputs.version }}
secrets: inherit
tag: ${{ github.event.inputs.version }}
secrets:
# needed for r2...
R2_INSTALL_ACCESS_KEY_ID: ${{ secrets.OSS_R2_INSTALL_ACCESS_KEY_ID }}
R2_INSTALL_SECRET_ACCESS_KEY: ${{ secrets.OSS_R2_INSTALL_SECRET_ACCESS_KEY }}
R2_ENDPOINT: ${{ secrets.TOOLBOX_CLOUDFLARE_R2_ENDPOINT }}
# needed for s3...
S3_INSTALL_AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
S3_INSTALL_AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
@@ -6,6 +6,10 @@ on:
jobs:
run:
permissions:
contents: read
issues: write
pull-requests: write
uses: "anchore/workflows/.github/workflows/remove-awaiting-response-label.yaml@main"
secrets:
token: ${{ secrets.OSS_PROJECT_GH_TOKEN }}
@@ -20,6 +20,8 @@ jobs:
packages: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -34,7 +36,9 @@ jobs:
DOWNLOAD_TEST_FIXTURE_CACHE: "false"
- name: Login to GitHub Container Registry (ORAS)
run: echo "${{ secrets.GITHUB_TOKEN }}" | .tool/oras login ghcr.io -u ${{ github.actor }} --password-stdin
run: echo "${{ secrets.GITHUB_TOKEN }}" | .tool/oras login ghcr.io -u "$ACTOR" --password-stdin
env:
ACTOR: ${{ github.actor }}
- name: Publish test fixture cache
run: make upload-test-fixture-cache
@@ -16,6 +16,8 @@ jobs:
if: github.repository_owner == 'anchore' # only run for main repo (not forks)
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -14,6 +14,8 @@ jobs:
if: github.repository == 'anchore/syft' # only run for main repo
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -17,6 +17,8 @@ jobs:
if: github.repository == 'anchore/syft' # only run for main repo
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -0,0 +1,35 @@
name: "Validate GitHub Actions"
on:
pull_request:
paths:
- '.github/workflows/**'
- '.github/actions/**'
push:
branches:
- main
paths:
- '.github/workflows/**'
- '.github/actions/**'
permissions:
contents: read
jobs:
zizmor:
name: "Lint"
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write # for uploading SARIF results
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: "Run zizmor"
uses: zizmorcore/zizmor-action@f52a838cfabf134edcbaa7c8b3677dde20045018 # v0.1.1
with:
config-file: .github/zizmor.yml
sarif-upload: true
inputs: .github
+27 -6
View File
@@ -18,6 +18,8 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -33,6 +35,8 @@ jobs:
runs-on: ubuntu-22.04-4core-16gb
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -49,6 +53,8 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -67,6 +73,8 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -76,10 +84,13 @@ jobs:
- name: Build snapshot artifacts
run: make snapshot
- name: Smoke test snapshot build
run: make snapshot-smoke-test
# why not use actions/upload-artifact? It is very slow (3 minutes to upload ~600MB of data, vs 10 seconds with this approach).
# see https://github.com/actions/upload-artifact/issues/199 for more info
- name: Upload snapshot artifacts
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
# we need to preserve the snapshot data itself as well as the task data that confirms if the
# snapshot build is stale or not. Otherwise the downstream jobs will attempt to rebuild the snapshot
@@ -97,6 +108,8 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -105,7 +118,7 @@ jobs:
- name: Download snapshot build
id: snapshot-cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
path: |
snapshot
@@ -152,6 +165,8 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -160,7 +175,7 @@ jobs:
- name: Download snapshot build
id: snapshot-cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
path: |
snapshot
@@ -195,9 +210,11 @@ jobs:
runs-on: macos-latest
steps:
- name: Install Cosign
uses: sigstore/cosign-installer@v3.8.2
uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -208,7 +225,7 @@ jobs:
- name: Download snapshot build
id: snapshot-cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
path: |
snapshot
@@ -235,6 +252,8 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
@@ -243,7 +262,7 @@ jobs:
- name: Download snapshot build
id: snapshot-cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 #v4.2.3
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4
with:
path: |
snapshot
@@ -273,6 +292,8 @@ jobs:
- Upload-Snapshot-Artifacts
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
persist-credentials: false
- name: Delete snapshot cache
run: gh cache delete "snapshot-build-${{ github.run_id }}"
+11
View File
@@ -0,0 +1,11 @@
rules:
unpinned-uses:
ignore:
# Allow unpinned uses of trusted internal anchore/workflows actions
- update-anchore-dependencies.yml
dangerous-triggers:
ignore:
# Safe use of pull_request_target - only runs trusted scripts from base repo,
# never checks out PR code, needs secrets for labeling PRs from forks
- detect-schema-changes.yaml
+187 -119
View File
@@ -1,11 +1,11 @@
version: 2
project_name: syft
release:
prerelease: auto
draft: false
env:
# required to support multi architecture docker builds
- DOCKER_CLI_EXPERIMENTAL=enabled
- CGO_ENABLED=0
@@ -13,14 +13,8 @@ builds:
- id: linux-build
dir: ./cmd/syft
binary: syft
goos:
- linux
goarch:
- amd64
- arm64
- ppc64le
- s390x
# set the modified timestamp on the output binary to the git timestamp to ensure a reproducible build
goos: [linux]
goarch: [amd64, arm64, ppc64le, s390x]
mod_timestamp: &build-timestamp '{{ .CommitTimestamp }}'
ldflags: &build-ldflags |
-w
@@ -34,11 +28,8 @@ builds:
- id: darwin-build
dir: ./cmd/syft
binary: syft
goos:
- darwin
goarch:
- amd64
- arm64
goos: [darwin]
goarch: [amd64, arm64]
mod_timestamp: *build-timestamp
ldflags: *build-ldflags
hooks:
@@ -50,115 +41,42 @@ builds:
- id: windows-build
dir: ./cmd/syft
binary: syft
goos:
- windows
goarch:
- amd64
goos: [windows]
goarch: [amd64]
mod_timestamp: *build-timestamp
ldflags: *build-ldflags
archives:
- id: linux-archives
builds:
- linux-build
# note: the signing process is depending on tar.gz archives. If this format changes then .github/scripts/apple-signing/*.sh will need to be adjusted
builds: [linux-build]
- id: darwin-archives
builds:
- darwin-build
builds: [darwin-build]
- id: windows-archives
format: zip
builds:
- windows-build
builds: [windows-build]
nfpms:
- license: "Apache 2.0"
maintainer: "Anchore, Inc"
homepage: &website "https://github.com/anchore/syft"
description: &description "A tool that generates a Software Bill Of Materials (SBOM) from container images and filesystems"
formats:
- rpm
- deb
formats: [rpm, deb]
brews:
- repository:
owner: anchore
name: homebrew-syft
token: "{{.Env.GITHUB_BREW_TOKEN}}"
ids:
- darwin-archives
- linux-archives
ids: [darwin-archives, linux-archives]
homepage: *website
description: *description
license: "Apache License 2.0"
dockers:
# production images...
- image_templates:
- anchore/syft:debug
- anchore/syft:{{.Tag}}-debug
- ghcr.io/anchore/syft:debug
- ghcr.io/anchore/syft:{{.Tag}}-debug
goarch: amd64
dockerfile: Dockerfile.debug
use: buildx
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:debug-arm64v8
- anchore/syft:{{.Tag}}-debug-arm64v8
- ghcr.io/anchore/syft:debug-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
goarch: arm64
dockerfile: Dockerfile.debug
use: buildx
build_flag_templates:
- "--platform=linux/arm64/v8"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:debug-ppc64le
- anchore/syft:{{.Tag}}-debug-ppc64le
- ghcr.io/anchore/syft:debug-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
goarch: ppc64le
dockerfile: Dockerfile.debug
use: buildx
build_flag_templates:
- "--platform=linux/ppc64le"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:debug-s390x
- anchore/syft:{{.Tag}}-debug-s390x
- ghcr.io/anchore/syft:debug-s390x
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
goarch: s390x
dockerfile: Dockerfile.debug
use: buildx
build_flag_templates:
- "--platform=linux/s390x"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:latest
- anchore/syft:{{.Tag}}
- ghcr.io/anchore/syft:latest
- ghcr.io/anchore/syft:{{.Tag}}
- anchore/syft:{{.Tag}}-amd64
- ghcr.io/anchore/syft:{{.Tag}}-amd64
goarch: amd64
dockerfile: Dockerfile
use: buildx
@@ -208,51 +126,201 @@ dockers:
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
# nonroot images...
- image_templates:
- anchore/syft:{{.Tag}}-nonroot-amd64
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-amd64
goarch: amd64
dockerfile: Dockerfile.nonroot
use: buildx
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-nonroot-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-arm64v8
goarch: arm64
dockerfile: Dockerfile.nonroot
use: buildx
build_flag_templates:
- "--platform=linux/arm64/v8"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-nonroot-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-ppc64le
goarch: ppc64le
dockerfile: Dockerfile.nonroot
use: buildx
build_flag_templates:
- "--platform=linux/ppc64le"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-nonroot-s390x
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-s390x
goarch: s390x
dockerfile: Dockerfile.nonroot
use: buildx
build_flag_templates:
- "--platform=linux/s390x"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
# debug images...
- image_templates:
- anchore/syft:{{.Tag}}-debug-amd64
- ghcr.io/anchore/syft:{{.Tag}}-debug-amd64
goarch: amd64
dockerfile: Dockerfile.debug
use: buildx
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-debug-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
goarch: arm64
dockerfile: Dockerfile.debug
use: buildx
build_flag_templates:
- "--platform=linux/arm64/v8"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-debug-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
goarch: ppc64le
dockerfile: Dockerfile.debug
use: buildx
build_flag_templates:
- "--platform=linux/ppc64le"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-debug-s390x
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
goarch: s390x
dockerfile: Dockerfile.debug
use: buildx
build_flag_templates:
- "--platform=linux/s390x"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
docker_manifests:
- name_template: anchore/syft:latest
image_templates:
- anchore/syft:{{.Tag}}
- anchore/syft:{{.Tag}}-arm64v8
- anchore/syft:{{.Tag}}-ppc64le
- anchore/syft:{{.Tag}}-s390x
- name_template: anchore/syft:debug
- anchore/syft:{{.Tag}}-debug
- anchore/syft:{{.Tag}}-debug-arm64v8
- anchore/syft:{{.Tag}}-debug-ppc64le
- anchore/syft:{{.Tag}}-debug-s390x
- name_template: anchore/syft:{{.Tag}}
image_templates:
- anchore/syft:{{.Tag}}
- anchore/syft:{{.Tag}}-amd64
- anchore/syft:{{.Tag}}-arm64v8
- anchore/syft:{{.Tag}}-ppc64le
- anchore/syft:{{.Tag}}-s390x
- name_template: ghcr.io/anchore/syft:latest
image_templates:
- ghcr.io/anchore/syft:{{.Tag}}
- ghcr.io/anchore/syft:{{.Tag}}-amd64
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-s390x
- name_template: anchore/syft:{{.Tag}}
image_templates:
- anchore/syft:{{.Tag}}-amd64
- anchore/syft:{{.Tag}}-arm64v8
- anchore/syft:{{.Tag}}-ppc64le
- anchore/syft:{{.Tag}}-s390x
- name_template: ghcr.io/anchore/syft:{{.Tag}}
image_templates:
- ghcr.io/anchore/syft:{{.Tag}}-amd64
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-s390x
# nonroot images...
- name_template: anchore/syft:nonroot
image_templates:
- anchore/syft:{{.Tag}}-nonroot-amd64
- anchore/syft:{{.Tag}}-nonroot-arm64v8
- anchore/syft:{{.Tag}}-nonroot-ppc64le
- anchore/syft:{{.Tag}}-nonroot-s390x
- name_template: ghcr.io/anchore/syft:nonroot
image_templates:
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-amd64
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-s390x
- name_template: anchore/syft:{{.Tag}}-nonroot
image_templates:
- anchore/syft:{{.Tag}}-nonroot-amd64
- anchore/syft:{{.Tag}}-nonroot-arm64v8
- anchore/syft:{{.Tag}}-nonroot-ppc64le
- anchore/syft:{{.Tag}}-nonroot-s390x
- name_template: ghcr.io/anchore/syft:{{.Tag}}-nonroot
image_templates:
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-amd64
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-s390x
# debug images...
- name_template: anchore/syft:debug
image_templates:
- anchore/syft:{{.Tag}}-debug-amd64
- anchore/syft:{{.Tag}}-debug-arm64v8
- anchore/syft:{{.Tag}}-debug-ppc64le
- anchore/syft:{{.Tag}}-debug-s390x
- name_template: ghcr.io/anchore/syft:debug
image_templates:
- ghcr.io/anchore/syft:{{.Tag}}-debug
- ghcr.io/anchore/syft:{{.Tag}}-debug-amd64
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
- name_template: ghcr.io/anchore/syft:{{.Tag}}
- name_template: anchore/syft:{{.Tag}}-debug
image_templates:
- ghcr.io/anchore/syft:{{.Tag}}
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-s390x
- anchore/syft:{{.Tag}}-debug-amd64
- anchore/syft:{{.Tag}}-debug-arm64v8
- anchore/syft:{{.Tag}}-debug-ppc64le
- anchore/syft:{{.Tag}}-debug-s390x
- name_template: ghcr.io/anchore/syft:{{.Tag}}-debug
image_templates:
- ghcr.io/anchore/syft:{{.Tag}}-debug-amd64
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
sboms:
- artifacts: archive
# this is relative to the snapshot/dist directory, not the root of the repo
cmd: ../.tool/syft
documents:
- "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.sbom"
+3 -1
View File
@@ -1,10 +1,12 @@
FROM gcr.io/distroless/static-debian12:debug
FROM gcr.io/distroless/static-debian12:debug-nonroot
# create the /tmp dir, which is needed for image content cache
WORKDIR /tmp
COPY syft /
USER nonroot
ARG BUILD_DATE
ARG BUILD_VERSION
ARG VCS_REF
+27
View File
@@ -0,0 +1,27 @@
FROM gcr.io/distroless/static-debian12:nonroot
# create the /tmp dir, which is needed for image content cache
WORKDIR /tmp
COPY syft /
USER nonroot
ARG BUILD_DATE
ARG BUILD_VERSION
ARG VCS_REF
ARG VCS_URL
LABEL org.opencontainers.image.created=$BUILD_DATE
LABEL org.opencontainers.image.title="syft"
LABEL org.opencontainers.image.description="CLI tool and library for generating a Software Bill of Materials from container images and filesystems"
LABEL org.opencontainers.image.source=$VCS_URL
LABEL org.opencontainers.image.revision=$VCS_REF
LABEL org.opencontainers.image.vendor="Anchore, Inc."
LABEL org.opencontainers.image.version=$BUILD_VERSION
LABEL org.opencontainers.image.licenses="Apache-2.0"
LABEL io.artifacthub.package.readme-url="https://raw.githubusercontent.com/anchore/syft/main/README.md"
LABEL io.artifacthub.package.logo-url="https://user-images.githubusercontent.com/5199289/136844524-1527b09f-c5cb-4aa9-be54-5aa92a6086c1.png"
LABEL io.artifacthub.package.license="Apache-2.0"
ENTRYPOINT ["/syft"]
+1 -1
View File
@@ -12,7 +12,7 @@ TASK = $(TOOL_DIR)/task
# note: we need to assume that binny and task have not already been installed
$(BINNY):
@mkdir -p $(TOOL_DIR)
@curl -sSfL https://raw.githubusercontent.com/$(OWNER)/binny/main/install.sh | sh -s -- -b $(TOOL_DIR)
@curl -sSfL https://get.anchore.io/binny | sh -s -- -b $(TOOL_DIR)
# note: we need to assume that binny and task have not already been installed
.PHONY: task
+6 -6
View File
@@ -37,8 +37,8 @@ Syft development is sponsored by [Anchore](https://anchore.com/), and is release
Syft binaries are provided for Linux, macOS and Windows.
### Recommended
> ```bash
> curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
> ```bash
> curl -sSfL https://get.anchore.io/syft | sudo sh -s -- -b /usr/local/bin
> ```
Install script options:
@@ -141,7 +141,7 @@ Note that flags using the @<version> can be used for earlier versions of each sp
- Linux kernel modules (ko)
- Nix (outputs in /nix/store)
- PHP (composer, PECL, Pear)
- Python (wheel, egg, poetry, requirements.txt)
- Python (wheel, egg, poetry, requirements.txt, uv)
- Red Hat (rpm)
- Ruby (gem)
- Rust (cargo.lock, auditable binary)
@@ -157,7 +157,7 @@ Our [wiki](https://github.com/anchore/syft/wiki) contains further details on the
* [File Selection](https://github.com/anchore/syft/wiki/file-selection)
* [Excluding file paths](https://github.com/anchore/syft/wiki/excluding-file-paths)
* [Output formats](https://github.com/anchore/syft/wiki/output-formats)
* [Package Cataloger Selection](https://github.com/anchore/syft/wiki/package-cataloger-selection)
* [Package Cataloger Selection](https://github.com/anchore/syft/wiki/package-cataloger-selection)
* [Concepts](https://github.com/anchore/syft/wiki/package-cataloger-selection#concepts)
* [Examples](https://github.com/anchore/syft/wiki/package-cataloger-selection#examples)
* [Using templates](https://github.com/anchore/syft/wiki/using-templates)
@@ -177,8 +177,8 @@ Check out our [contributing](/CONTRIBUTING.md) guide and [developer](/DEVELOPING
## 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.
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!
+38 -57
View File
@@ -27,10 +27,12 @@ vars:
sh: uname -s | tr '[:upper:]' '[:lower:]'
ARCH:
sh: |
[ "$(uname -m)" = "x86_64" ] && echo "amd64_v1" || { [ "$(uname -m)" = "aarch64" ] && echo "arm64_v8.0" || echo $(uname -m); }
[ "$(uname -m)" = "x86_64" ] && echo "amd64_v1" || { [ "$(uname -m)" = "aarch64" ] && echo "arm64_v8.0" || [ "$(uname -m)" = "arm64" ] && echo "arm64_v8.0" || echo $(uname -m); }
PROJECT_ROOT:
sh: echo $PWD
# note: the snapshot dir must be a relative path starting with ./
# e.g. when installing snapshot debs from a local path, ./ forces the deb to be installed in the current working directory instead of referencing a package name
SNAPSHOT_DIR: ./snapshot
SNAPSHOT_BIN: "{{ .PROJECT_ROOT }}/{{ .SNAPSHOT_DIR }}/{{ .OS }}-build_{{ .OS }}_{{ .ARCH }}/{{ .PROJECT }}"
SNAPSHOT_CMD: "{{ .TOOL_DIR }}/goreleaser release --config {{ .TMP_DIR }}/goreleaser.yaml --clean --snapshot --skip=publish --skip=sign"
@@ -76,6 +78,7 @@ tasks:
- task: integration
- task: validate-cyclonedx-schema
- task: test-utils
- task: snapshot
- task: cli
- task: check-docker-cache
@@ -88,7 +91,7 @@ tasks:
- "{{ .TOOL_DIR }}/binny"
status:
- "test -f {{ .TOOL_DIR }}/binny"
cmd: "curl -sSfL https://raw.githubusercontent.com/anchore/binny/main/install.sh | sh -s -- -b .tool"
cmd: "curl -sSfL https://get.anchore.io/binny | sh -s -- -b .tool"
silent: true
tools:
@@ -230,10 +233,7 @@ tasks:
cli:
desc: Run CLI tests
# note: we don't want to regenerate the snapshot unless we have to. In CI it's probable
# that the cache being restored with the correct binary will be rebuilt since the timestamps
# and local checksums will not line up.
deps: [tools, snapshot]
deps: [tools]
cmds:
- cmd: "echo 'testing binary: {{ .SNAPSHOT_BIN }}'"
silent: true
@@ -250,27 +250,6 @@ tasks:
- cmd: .github/scripts/labeler_test.py
## Benchmark test targets #################################
benchmark:
deps: [tmpdir]
generates:
- "{{ .TMP_DIR }}/benchmark-main.txt"
cmds:
- "go test -p 1 -run=^Benchmark -bench=. -count=7 -benchmem ./... | tee {{ .TMP_DIR }}/benchmark-{{ .VERSION }}.txt"
- |
bash -c "(test -s {{ .TMP_DIR }}/benchmark-main.txt && \
{{ .TOOL_DIR }}/benchstat {{ .TMP_DIR }}/benchmark-main.txt {{ .TMP_DIR }}/benchmark-{{ .VERSION }}.txt || \
{{ .TOOL_DIR }}/benchstat {{ .TMP_DIR }}/benchmark-{{ .VERSION }}.txt) \
| tee {{ .TMP_DIR }}/benchstat.txt"
show-benchstat:
deps: [benchmark, tmpdir]
cmds:
- cmd: "cat {{ .TMP_DIR }}/benchstat.txt"
silent: true
## Test-fixture-related targets #################################
fingerprints:
@@ -286,12 +265,12 @@ tasks:
YELLOW='\033[0;33m'
RESET='\033[0m'
echo -e "${YELLOW}creating fingerprint files for non-docker fixtures...${RESET}"
echo -e "${YELLOW}creating fingerprint files for non-docker fixtures...${RESET}"
for dir in $(find . -type d -name 'test-fixtures'); do
if [ -f "$dir/Makefile" ]; then
# for debugging...
#echo -e "${YELLOW}• calculating fingerprints in $dir... ${RESET}"
(make -C "$dir" fingerprint)
fi
done
@@ -320,18 +299,18 @@ tasks:
BOLD='\033[1m'
PURPLE='\033[0;35m'
RESET='\033[0m'
# if DOWNLOAD_TEST_FIXTURE_CACHE is set to 'false', then skip the cache download and always build
if [ "$DOWNLOAD_TEST_FIXTURE_CACHE" = "false" ]; then
echo -e "${BOLD}${PURPLE}skipping cache download, rebuilding cache...${RESET}"
{{ .TASK }} build-fixtures
exit 0
fi
LATEST_FINGERPRINT=$(docker manifest inspect {{ .CACHE_IMAGE }} | {{ .YQ }} -r '.annotations.fingerprint')
echo "latest cache: $LATEST_FINGERPRINT"
if [ -f {{ .LAST_CACHE_PULL_FILE }} ]; then
LAST_PULL_FINGERPRINT=$(cat {{ .LAST_CACHE_PULL_FILE }} | {{ .YQ }} -r '.digest')
else
@@ -339,41 +318,41 @@ tasks:
{{ .TASK }} download-test-fixture-cache
exit 0
fi
{{ .TASK }} fingerprints
WANT_FINGERPRINT=$(cat {{ .CACHE_PATHS_FILE }} | {{ .YQ }} -r '.digest')
WANT_FINGERPRINT=$(cat {{ .CACHE_PATHS_FILE }} | {{ .YQ }} -r '.digest')
echo "desired cache: $WANT_FINGERPRINT"
echo "last pulled cache: $LAST_PULL_FINGERPRINT"
# if we already have the latest cache, skip the refresh
if [ "$LAST_PULL_FINGERPRINT" = "$WANT_FINGERPRINT" ]; then
echo -e "${BOLD}${PURPLE}already have the latest cache (skipping cache download)${RESET}"
exit 0
fi
# at this point we only refresh the cache if we want the same cache that is currently available.
# we don't by default refresh the cache if the cache if it is simply different from what we have,
# because we may be working on a code change that doesn't require a cache refresh (but could trigger one,
# which would be annoying to deal with in a development workflow).
if [ "$LATEST_FINGERPRINT" = "$WANT_FINGERPRINT" ]; then
echo -e "${BOLD}${PURPLE}found newer cache! downloading cache...${RESET}"
{{ .TASK }} download-test-fixture-cache
else
echo -e "${BOLD}${PURPLE}found different cache, but isn't clear if it's newer (skipping cache download and manually building)${RESET}"
{{ .YQ }} eval '.paths[] | "\(.digest) \(.path)"' {{ .LAST_CACHE_PULL_FILE }} > .tmp/last_cache_lines
{{ .YQ }} eval '.paths[] | "\(.digest) \(.path)"' {{ .CACHE_PATHS_FILE }} > .tmp/cache_lines
diff .tmp/last_cache_lines .tmp/cache_lines || true
echo -e "${BOLD}${PURPLE}diff with more context...${RESET}"
diff -U10000 {{ .LAST_CACHE_PULL_FILE }} {{ .CACHE_PATHS_FILE }} || true
echo -e "${BOLD}${PURPLE}detected changes to input material, manually building fixtures...${RESET}"
{{ .TASK }} build-fixtures
fi
@@ -386,7 +365,7 @@ tasks:
BOLD='\033[1m'
YELLOW='\033[0;33m'
RESET='\033[0m'
# Use a for loop with command substitution to avoid subshell issues
for dir in $(find . -type d -name 'test-fixtures'); do
if [ -f "$dir/Makefile" ]; then
@@ -424,15 +403,15 @@ tasks:
set -eu
oras_command="{{ .ORAS }} push {{ .CACHE_IMAGE }}"
paths=$(cat {{ .CACHE_PATHS_FILE }} | {{ .YQ }} -r '.paths[].path')
paths=$(cat {{ .CACHE_PATHS_FILE }} | {{ .YQ }} -r '.paths[].path')
for path in $paths; do
oras_command+=" $path"
done
oras_command+=" {{ .CACHE_PATHS_FILE }}"
oras_command+=" --annotation org.opencontainers.image.source=https://github.com/{{ .OWNER }}/{{ .PROJECT }}"
oras_command+=" --annotation fingerprint=$(cat {{ .CACHE_PATHS_FILE }} | {{ .YQ }} -r '.digest')"
echo "Executing: $oras_command"
eval $oras_command
@@ -573,6 +552,18 @@ tasks:
- "{{ .SNAPSHOT_CMD }}"
snapshot-smoke-test:
desc: Run a smoke test on the snapshot builds + docker images
cmds:
- cmd: "echo 'testing snapshot binary: {{ .SNAPSHOT_BIN }}'"
silent: true
- cmd: "test -f {{ .SNAPSHOT_BIN }} || (find {{ .SNAPSHOT_DIR }} && echo '\nno snapshot found for {{ .SNAPSHOT_BIN }}' && false)"
silent: true
- "{{ .SNAPSHOT_BIN }} version"
- "{{ .SNAPSHOT_BIN }} scan alpine:latest"
- docker run --rm anchore/syft:latest version
- docker run --rm anchore/syft:latest scan alpine:latest
changelog:
desc: Generate a changelog
deps: [tools]
@@ -613,16 +604,6 @@ tasks:
silent: true
- "{{ .RELEASE_CMD }}"
ci-release-version-file:
# desc: "[CI only] Update the version file"
deps: [tools]
cmds:
- task: ci-check
- ".github/scripts/update-version-file.sh {{ .RELEASE_VERSION }}"
requires:
vars:
- RELEASE_VERSION
## Cleanup targets #################################
@@ -650,7 +631,7 @@ tasks:
BOLD='\033[1m'
YELLOW='\033[0;33m'
RESET='\033[0m'
# Use a for loop with command substitution to avoid subshell issues
for dir in $(find . -type d -name 'test-fixtures'); do
if [ -f "$dir/Makefile" ]; then
+6 -1
View File
@@ -10,6 +10,7 @@ import (
"github.com/anchore/clio"
"github.com/anchore/syft/cmd/syft/internal"
"github.com/anchore/syft/cmd/syft/internal/commands"
constants "github.com/anchore/syft/internal"
)
// Application constructs the `syft packages` command and aliases the root command to `syft packages`.
@@ -47,7 +48,7 @@ func create(id clio.Identification, out io.Writer) (clio.Application, *cobra.Com
commands.Cataloger(app),
commands.Attest(app),
commands.Convert(app),
clio.VersionCommand(id),
clio.VersionCommand(id, schemaVersion),
clio.ConfigCommand(app, nil),
cranecmd.NewCmdAuthLogin(id.Name), // syft login uses the same command as crane
)
@@ -59,3 +60,7 @@ func create(id clio.Identification, out io.Writer) (clio.Application, *cobra.Com
return app, rootCmd
}
func schemaVersion() (string, any) {
return "SchemaVersion", constants.JSONSchemaVersion
}
@@ -0,0 +1,8 @@
[TestHandler_handlePullSourceStarted/snap_download_in_progress - 1]
⠋ Downloading snap file... ━━━━━━━━━━━━━━━━━━━━ example-app_1.0_amd64.snap
---
[TestHandler_handlePullSourceStarted/snap_download_complete - 1]
✔ Snap downloaded successfully example-app_1.0_amd64.snap
---
@@ -26,7 +26,7 @@ func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
{
name: "cataloging task in progress",
eventFn: func(t *testing.T) partybus.Event {
value := &monitor.CatalogerTaskProgress{
value := &monitor.TaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
@@ -48,7 +48,7 @@ func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
{
name: "cataloging sub task in progress",
eventFn: func(t *testing.T) partybus.Event {
value := &monitor.CatalogerTaskProgress{
value := &monitor.TaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
@@ -71,7 +71,7 @@ func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
{
name: "cataloging sub task complete",
eventFn: func(t *testing.T) partybus.Event {
value := &monitor.CatalogerTaskProgress{
value := &monitor.TaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
@@ -94,7 +94,7 @@ func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
{
name: "cataloging sub task complete -- hide stage",
eventFn: func(t *testing.T) partybus.Event {
value := &monitor.CatalogerTaskProgress{
value := &monitor.TaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
@@ -117,7 +117,7 @@ func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
{
name: "cataloging sub task complete with removal",
eventFn: func(t *testing.T) partybus.Event {
value := &monitor.CatalogerTaskProgress{
value := &monitor.TaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
@@ -162,7 +162,7 @@ func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
}
// note: this line / event is not under test, only needed to show a sub status
kickoffEvent := &monitor.CatalogerTaskProgress{
kickoffEvent := &monitor.TaskProgress{
AtomicStage: progress.NewAtomicStage(""),
Manual: progress.NewManual(-1),
}
+37
View File
@@ -0,0 +1,37 @@
package ui
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/wagoodman/go-partybus"
"github.com/anchore/bubbly/bubbles/taskprogress"
"github.com/anchore/syft/internal/log"
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
)
func (m *Handler) handlePullSourceStarted(e partybus.Event) []tea.Model {
prog, info, err := syftEventParsers.ParsePullSourceStarted(e)
if err != nil {
log.WithFields("error", err).Debug("unable to parse event")
return nil
}
tsk := m.newTaskProgress(
taskprogress.Title{
Default: info.Title.Default,
Running: info.Title.WhileRunning,
Success: info.Title.OnSuccess,
},
taskprogress.WithStagedProgressable(prog),
)
tsk.HideOnSuccess = info.HideOnSuccess
tsk.HideStageOnSuccess = info.HideStageOnSuccess
tsk.HideProgressOnSuccess = true
if info.Context != "" {
tsk.Context = []string{info.Context}
}
return []tea.Model{tsk}
}
+121
View File
@@ -0,0 +1,121 @@
package ui
import (
"testing"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/gkampitakis/go-snaps/snaps"
"github.com/stretchr/testify/require"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/bubbly/bubbles/taskprogress"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/monitor"
)
func TestHandler_handlePullSourceStarted(t *testing.T) {
tests := []struct {
name string
eventFn func(*testing.T) partybus.Event
iterations int
}{
{
name: "snap download in progress",
eventFn: func(t *testing.T) partybus.Event {
stage := progress.NewAtomicStage("")
manual := progress.NewManual(0)
manual.SetTotal(1000000) // 1MB file
manual.Set(250000) // 25% downloaded
taskProg := &monitor.TaskProgress{
AtomicStage: stage,
Manual: manual,
}
genericTask := monitor.GenericTask{
Title: monitor.Title{
Default: "Downloading snap",
WhileRunning: "Downloading snap file...",
OnSuccess: "Snap downloaded",
},
Context: "example-app_1.0_amd64.snap",
HideOnSuccess: false,
HideStageOnSuccess: true,
ID: "snap-download-123",
}
return partybus.Event{
Type: event.PullSourceStarted,
Source: genericTask,
Value: taskProg,
}
},
iterations: 5,
},
{
name: "snap download complete",
eventFn: func(t *testing.T) partybus.Event {
stage := progress.NewAtomicStage("")
manual := progress.NewManual(0)
manual.SetTotal(1000000) // 1MB file
manual.Set(1000000) // 100% downloaded
manual.SetCompleted()
taskProg := &monitor.TaskProgress{
AtomicStage: stage,
Manual: manual,
}
genericTask := monitor.GenericTask{
Title: monitor.Title{
Default: "Downloading snap",
WhileRunning: "Downloading snap file...",
OnSuccess: "Snap downloaded successfully",
},
Context: "example-app_1.0_amd64.snap",
HideOnSuccess: false,
HideStageOnSuccess: true,
ID: "snap-download-123",
}
return partybus.Event{
Type: event.PullSourceStarted,
Source: genericTask,
Value: taskProg,
}
},
iterations: 3,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
event := tt.eventFn(t)
handler := New(DefaultHandlerConfig())
handler.WindowSize = tea.WindowSizeMsg{
Width: 100,
Height: 80,
}
models := handler.handlePullSourceStarted(event)
require.Len(t, models, 1)
model := models[0]
tsk, ok := model.(taskprogress.Model)
require.True(t, ok)
gotModel := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
Time: time.Now(),
Sequence: tsk.Sequence(),
ID: tsk.ID(),
})
got := gotModel.View()
t.Log(got)
snaps.MatchSnapshot(t, got)
})
}
}
+1
View File
@@ -57,6 +57,7 @@ func New(cfg HandlerConfig) *Handler {
stereoscopeEvent.FetchImage: simpleHandler(h.handleFetchImage),
syftEvent.FileIndexingStarted: simpleHandler(h.handleFileIndexingStarted),
syftEvent.AttestationStarted: simpleHandler(h.handleAttestationStarted),
syftEvent.PullSourceStarted: simpleHandler(h.handlePullSourceStarted),
syftEvent.CatalogerTaskStarted: h.handleCatalogerTaskStarted,
})
+1 -1
View File
@@ -44,7 +44,7 @@ func AppClioSetupConfig(id clio.Identification, out io.Writer) *clio.SetupConfig
redact.Set(state.RedactStore)
log.Set(state.Logger)
stereoscope.SetLogger(state.Logger)
stereoscope.SetLogger(state.Logger.Nested("from", "stereoscope"))
return nil
},
).
@@ -33,7 +33,7 @@ func TestPackageDeduplication(t *testing.T) {
"curl-minimal-7.76.1-31.el9": 3, // curl upgrade layer + all above layers
"wget-1.21.1-8.el9_4": 4, // wget + all above layers
"vsftpd-3.0.5-6.el9": 2, // vsftpd + all above layers
"httpd-2.4.62-1.el9_5.2": 1, // last layer
"httpd-2.4.62-4.el9": 1, // last layer
},
},
{
@@ -51,7 +51,7 @@ func TestPackageDeduplication(t *testing.T) {
"curl-minimal-7.76.1-31.el9": 1, // upgrade
"wget-1.21.1-8.el9_4": 1,
"vsftpd-3.0.5-6.el9": 1,
"httpd-2.4.62-1.el9_5.2": 1,
"httpd-2.4.62-4.el9": 1,
},
},
}
+70 -40
View File
@@ -5,7 +5,7 @@ go 1.24.1
require (
github.com/BurntSushi/toml v1.5.0
github.com/CycloneDX/cyclonedx-go v0.9.2
github.com/Masterminds/semver/v3 v3.3.1
github.com/Masterminds/semver/v3 v3.4.0
github.com/Masterminds/sprig/v3 v3.3.0
github.com/OneOfOne/xxhash v1.2.8
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
@@ -24,45 +24,48 @@ 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.20250220190351-d62adb6e1115
github.com/anchore/stereoscope v0.1.4
github.com/anchore/stereoscope v0.1.8
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
github.com/aquasecurity/go-pep440-version v0.0.1
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/bmatcuk/doublestar/v4 v4.8.1
github.com/bmatcuk/doublestar/v4 v4.9.1
github.com/charmbracelet/bubbles v0.21.0
github.com/charmbracelet/bubbletea v1.3.5
github.com/charmbracelet/bubbletea v1.3.6
github.com/charmbracelet/lipgloss v1.1.0
github.com/dave/jennifer v1.7.1
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
github.com/diskfs/go-diskfs v1.6.1-0.20250601133945-2af1c7ece24c
github.com/distribution/reference v0.6.0
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.3.3
github.com/gkampitakis/go-snaps v0.5.11
github.com/gkampitakis/go-snaps v0.5.14
github.com/go-git/go-billy/v5 v5.6.2
github.com/go-git/go-git/v5 v5.16.0
github.com/go-git/go-git/v5 v5.16.2
github.com/go-test/deep v1.1.1
github.com/go-viper/mapstructure/v2 v2.2.1
github.com/go-viper/mapstructure/v2 v2.4.0
github.com/gohugoio/hashstructure v0.5.0
github.com/google/go-cmp v0.7.0
github.com/google/go-containerregistry v0.20.4
github.com/google/go-containerregistry v0.20.6
github.com/google/licensecheck v0.3.1
github.com/google/uuid v1.6.0
github.com/gookit/color v1.5.4
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-getter v1.7.8
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/hcl/v2 v2.23.0
github.com/hashicorp/hcl/v2 v2.24.0
github.com/iancoleman/strcase v0.3.0
github.com/invopop/jsonschema v0.7.0
github.com/jedib0t/go-pretty/v6 v6.6.7
github.com/jedib0t/go-pretty/v6 v6.6.8
github.com/jinzhu/copier v0.4.0
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
github.com/magiconair/properties v1.8.10
github.com/mholt/archives v0.1.2
github.com/mholt/archives v0.1.3
github.com/moby/sys/mountinfo v0.7.2
github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1
github.com/olekukonko/tablewriter v0.0.5
github.com/olekukonko/tablewriter v1.0.9
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
@@ -72,7 +75,7 @@ require (
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/sergi/go-diff v1.4.0
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb
github.com/spdx/tools-golang v0.5.5
github.com/spf13/afero v1.14.0
@@ -85,14 +88,20 @@ require (
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/exp v0.0.0-20250305212735-054e65f0b394
golang.org/x/mod v0.24.0
golang.org/x/net v0.40.0
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
golang.org/x/mod v0.27.0
golang.org/x/net v0.43.0
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.37.0
modernc.org/sqlite v1.38.2
)
require (
cloud.google.com/go v0.116.0 // indirect
cloud.google.com/go/auth v0.9.9 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
cloud.google.com/go/compute/metadata v0.7.0 // indirect
cloud.google.com/go/iam v1.2.2 // indirect
cloud.google.com/go/storage v1.43.0 // indirect
dario.cat/mergo v1.0.1 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect
@@ -103,20 +112,22 @@ require (
github.com/ProtonMail/go-crypto v1.2.0 // indirect
github.com/STARRY-S/zip v0.2.1 // indirect
github.com/agext/levenshtein v1.2.1 // indirect; indirectt
github.com/anchore/go-lzo v0.1.0 // indirect
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/aquasecurity/go-version v0.0.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aws/aws-sdk-go v1.44.122 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bodgit/plumbing v1.3.0 // indirect
github.com/bodgit/sevenzip v1.6.0 // indirect
github.com/bodgit/windows v1.0.1 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/harmonica v0.2.0 // indirect
github.com/charmbracelet/x/ansi v0.8.0 // indirect
github.com/charmbracelet/x/ansi v0.9.3 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
@@ -124,18 +135,19 @@ require (
github.com/containerd/containerd v1.7.27 // indirect
github.com/containerd/containerd/api v1.8.0 // indirect
github.com/containerd/continuity v0.4.4 // indirect
github.com/containerd/errdefs v0.3.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/containerd/typeurl/v2 v2.2.0 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/cli v28.1.1+incompatible // indirect
github.com/docker/cli v28.3.2+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v28.1.1+incompatible // indirect
github.com/docker/docker v28.3.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
@@ -143,27 +155,34 @@ require (
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/felixge/fgprof v0.9.5 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
github.com/gkampitakis/ciinfo v0.3.1 // indirect
github.com/gkampitakis/ciinfo v0.3.2 // indirect
github.com/gkampitakis/go-diff v1.3.2 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-restruct/restruct v1.2.0-alpha // indirect
github.com/goccy/go-yaml v1.15.13 // indirect
github.com/goccy/go-yaml v1.18.0
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
@@ -177,9 +196,11 @@ require (
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mikelolasagasti/xz v1.0.1 // indirect
github.com/minio/minlz v1.0.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
@@ -194,6 +215,8 @@ require (
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/nwaples/rardecode/v2 v2.1.0 // indirect
github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.0.9 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runtime-spec v1.1.0 // indirect
github.com/opencontainers/selinux v1.11.0 // indirect
@@ -203,6 +226,7 @@ require (
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/profile v1.7.0 // indirect
github.com/pkg/xattr v0.4.9 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
@@ -210,13 +234,14 @@ require (
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sahilm/fuzzy v0.1.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/sorairolake/lzip-go v0.3.5 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/spf13/viper v1.20.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/sylabs/sif/v2 v2.21.1 // indirect
github.com/sylabs/squashfs v1.0.6 // indirect
@@ -232,31 +257,36 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/zclconf/go-cty v1.13.0 // indirect
github.com/zclconf/go-cty v1.16.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/tools v0.33.0 // indirect
golang.org/x/crypto v0.41.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/term v0.34.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.35.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/api v0.203.0 // indirect
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
google.golang.org/grpc v1.67.3 // indirect
google.golang.org/protobuf v1.36.4 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
modernc.org/libc v1.62.1 // indirect
modernc.org/libc v1.66.3 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.9.1 // indirect
modernc.org/memory v1.11.0 // indirect
)
retract (
+1115 -93
View File
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -6,7 +6,8 @@ PROJECT_NAME=syft
OWNER=anchore
REPO="${PROJECT_NAME}"
GITHUB_DOWNLOAD_PREFIX=https://github.com/${OWNER}/${REPO}/releases/download
INSTALL_SH_BASE_URL=https://raw.githubusercontent.com/${OWNER}/${PROJECT_NAME}
INSTALL_SH_BASE_URL=https://get.anchore.io/${PROJECT_NAME}
LEGACY_INSTALL_SH_BASE_URL=https://raw.githubusercontent.com/${OWNER}/${PROJECT_NAME}
PROGRAM_ARGS=$@
# signature verification options
@@ -836,7 +837,11 @@ EOF
if [ "${DOWNLOAD_TAG_INSTALL_SCRIPT}" = "true" ]; then
export DOWNLOAD_TAG_INSTALL_SCRIPT=false
log_info "fetching release script for tag='${tag}'"
http_copy "${INSTALL_SH_BASE_URL}/${tag}/install.sh" "" | sh -s -- ${PROGRAM_ARGS}
if ! install_script=$(http_copy "${INSTALL_SH_BASE_URL}/${tag}/install.sh" ""); then
log_warn "failed to fetch from ${INSTALL_SH_BASE_URL}, trying fallback URL"
install_script=$(http_copy "${LEGACY_INSTALL_SH_BASE_URL}/${tag}/install.sh" "")
fi
echo "${install_script}" | sh -s -- ${PROGRAM_ARGS}
exit $?
fi
+32 -2
View File
@@ -36,8 +36,8 @@ func Notify(message string) {
})
}
func StartCatalogerTask(info monitor.GenericTask, size int64, initialStage string) *monitor.CatalogerTaskProgress {
t := &monitor.CatalogerTaskProgress{
func StartCatalogerTask(info monitor.GenericTask, size int64, initialStage string) *monitor.TaskProgress {
t := &monitor.TaskProgress{
AtomicStage: progress.NewAtomicStage(initialStage),
Manual: progress.NewManual(size),
}
@@ -50,3 +50,33 @@ func StartCatalogerTask(info monitor.GenericTask, size int64, initialStage strin
return t
}
func StartPullSourceTask(info monitor.GenericTask, size int64, initialStage string) *monitor.TaskProgress {
t := &monitor.TaskProgress{
AtomicStage: progress.NewAtomicStage(initialStage),
Manual: progress.NewManual(size),
}
Publish(partybus.Event{
Type: event.PullSourceStarted,
Source: info,
Value: progress.StagedProgressable(t),
})
return t
}
func StartIndexingFiles(path string) *monitor.TaskProgress {
t := &monitor.TaskProgress{
AtomicStage: progress.NewAtomicStage(""),
Manual: progress.NewManual(-1),
}
Publish(partybus.Event{
Type: event.FileIndexingStarted,
Source: path,
Value: progress.StagedProgressable(t),
})
return t
}
+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.34"
JSONSchemaVersion = "16.0.36"
)
+154
View File
@@ -0,0 +1,154 @@
package file
import (
"fmt"
"io"
"net/http"
"github.com/hashicorp/go-getter"
"github.com/hashicorp/go-getter/helper/url"
"github.com/wagoodman/go-progress"
"github.com/anchore/clio"
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/internal"
)
var (
archiveExtensions = getterDecompressorNames()
ErrNonArchiveSource = fmt.Errorf("non-archive sources are not supported for directory destinations")
)
type Getter interface {
// GetFile downloads the give URL into the given path. The URL must reference a single file.
GetFile(dst, src string, monitor ...*progress.Manual) error
// GetToDir downloads the resource found at the `src` URL into the given `dst` directory.
// The directory must already exist, and the remote resource MUST BE AN ARCHIVE (e.g. `.tar.gz`).
GetToDir(dst, src string, monitor ...*progress.Manual) error
}
type HashiGoGetter struct {
httpGetter getter.HttpGetter
}
// NewGetter creates and returns a new Getter. Providing an http.Client is optional. If one is provided,
// it will be used for all HTTP(S) getting; otherwise, go-getter's default getters will be used.
func NewGetter(id clio.Identification, httpClient *http.Client) *HashiGoGetter {
return &HashiGoGetter{
httpGetter: getter.HttpGetter{
Client: httpClient,
Header: http.Header{
"User-Agent": []string{fmt.Sprintf("%v %v", id.Name, id.Version)},
},
},
}
}
func (g HashiGoGetter) GetFile(dst, src string, monitors ...*progress.Manual) error {
if len(monitors) > 1 {
return fmt.Errorf("multiple monitors provided, which is not allowed")
}
return getterClient(dst, src, false, g.httpGetter, monitors).Get()
}
func (g HashiGoGetter) GetToDir(dst, src string, monitors ...*progress.Manual) error {
// though there are multiple getters, only the http/https getter requires extra validation
if err := validateHTTPSource(src); err != nil {
return err
}
if len(monitors) > 1 {
return fmt.Errorf("multiple monitors provided, which is not allowed")
}
return getterClient(dst, src, true, g.httpGetter, monitors).Get()
}
func validateHTTPSource(src string) error {
// we are ignoring any sources that are not destined to use the http getter object
if !internal.HasAnyOfPrefixes(src, "http://", "https://") {
return nil
}
u, err := url.Parse(src)
if err != nil {
return fmt.Errorf("bad URL provided %q: %w", src, err)
}
// only allow for sources with archive extensions
if !internal.HasAnyOfSuffixes(u.Path, archiveExtensions...) {
return ErrNonArchiveSource
}
return nil
}
func getterClient(dst, src string, dir bool, httpGetter getter.HttpGetter, monitors []*progress.Manual) *getter.Client {
client := &getter.Client{
Src: src,
Dst: dst,
Dir: dir,
Getters: map[string]getter.Getter{
"http": &httpGetter,
"https": &httpGetter,
// note: these are the default getters from https://github.com/hashicorp/go-getter/blob/v1.5.9/get.go#L68-L74
// it is possible that other implementations need to account for custom httpclient injection, however,
// that has not been accounted for at this time.
"file": new(getter.FileGetter),
"git": new(getter.GitGetter),
"gcs": new(getter.GCSGetter),
"hg": new(getter.HgGetter),
"s3": new(getter.S3Getter),
},
Options: mapToGetterClientOptions(monitors),
}
return client
}
func withProgress(monitor *progress.Manual) func(client *getter.Client) error {
return getter.WithProgress(
&progressAdapter{monitor: monitor},
)
}
func mapToGetterClientOptions(monitors []*progress.Manual) []getter.ClientOption {
var result []getter.ClientOption
for _, monitor := range monitors {
result = append(result, withProgress(monitor))
}
// derived from https://github.com/hashicorp/go-getter/blob/v2.2.3/decompress.go#L23-L63
fileSizeLimit := int64(5 * file.GB)
dec := getter.LimitedDecompressors(0, fileSizeLimit)
result = append(result, getter.WithDecompressors(dec))
return result
}
type readCloser struct {
progress.Reader
}
func (c *readCloser) Close() error { return nil }
type progressAdapter struct {
monitor *progress.Manual
}
func (a *progressAdapter) TrackProgress(_ string, currentSize, totalSize int64, stream io.ReadCloser) io.ReadCloser {
a.monitor.Set(currentSize)
a.monitor.SetTotal(totalSize)
return &readCloser{
Reader: *progress.NewProxyReader(stream, a.monitor),
}
}
func getterDecompressorNames() (names []string) {
for name := range getter.Decompressors {
names = append(names, name)
}
return names
}
+268
View File
@@ -0,0 +1,268 @@
package file
import (
"archive/tar"
"bytes"
"context"
"crypto/x509"
"fmt"
"net"
"net/http"
"net/http/httptest"
"net/url"
"path"
"testing"
"github.com/stretchr/testify/assert"
"github.com/anchore/clio"
)
func TestGetter_GetFile(t *testing.T) {
testCases := []struct {
name string
prepareClient func(*http.Client)
assert assert.ErrorAssertionFunc
}{
{
name: "client trusts server's CA",
assert: assert.NoError,
},
{
name: "client doesn't trust server's CA",
prepareClient: removeTrustedCAs,
assert: assertUnknownAuthorityError,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
requestPath := "/foo"
server := newTestServer(t, withResponseForPath(t, requestPath, testFileContent))
t.Cleanup(server.Close)
httpClient := getClient(t, server)
if tc.prepareClient != nil {
tc.prepareClient(httpClient)
}
getter := NewGetter(testID, httpClient)
requestURL := createRequestURL(t, server, requestPath)
tempDir := t.TempDir()
tempFile := path.Join(tempDir, "some-destination-file")
err := getter.GetFile(tempFile, requestURL)
tc.assert(t, err)
})
}
}
func TestGetter_GetToDir_FilterNonArchivesWired(t *testing.T) {
testCases := []struct {
name string
source string
assert assert.ErrorAssertionFunc
}{
{
name: "error out on non-archive sources",
source: "http://localhost/something.txt",
assert: assertErrNonArchiveSource,
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
test.assert(t, NewGetter(testID, nil).GetToDir(t.TempDir(), test.source))
})
}
}
func TestGetter_validateHttpSource(t *testing.T) {
testCases := []struct {
name string
source string
assert assert.ErrorAssertionFunc
}{
{
name: "error out on non-archive sources",
source: "http://localhost/something.txt",
assert: assertErrNonArchiveSource,
},
{
name: "filter out non-archive sources with get param",
source: "https://localhost/vulnerability-db_v3_2021-11-21T08:15:44Z.txt?checksum=sha256%3Ac402d01fa909a3fa85a5c6733ef27a3a51a9105b6c62b9152adbd24c08358911",
assert: assertErrNonArchiveSource,
},
{
name: "ignore non http-https input",
source: "s3://bucket/something.txt",
assert: assert.NoError,
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
test.assert(t, validateHTTPSource(test.source))
})
}
}
func TestGetter_GetToDir_CertConcerns(t *testing.T) {
testCases := []struct {
name string
prepareClient func(*http.Client)
assert assert.ErrorAssertionFunc
}{
{
name: "client trusts server's CA",
assert: assert.NoError,
},
{
name: "client doesn't trust server's CA",
prepareClient: removeTrustedCAs,
assert: assertUnknownAuthorityError,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
requestPath := "/foo.tar"
tarball := createTarball("foo", testFileContent)
server := newTestServer(t, withResponseForPath(t, requestPath, tarball))
t.Cleanup(server.Close)
httpClient := getClient(t, server)
if tc.prepareClient != nil {
tc.prepareClient(httpClient)
}
getter := NewGetter(testID, httpClient)
requestURL := createRequestURL(t, server, requestPath)
tempDir := t.TempDir()
err := getter.GetToDir(tempDir, requestURL)
tc.assert(t, err)
})
}
}
func assertUnknownAuthorityError(t assert.TestingT, err error, _ ...interface{}) bool {
return assert.ErrorAs(t, err, &x509.UnknownAuthorityError{})
}
func assertErrNonArchiveSource(t assert.TestingT, err error, _ ...interface{}) bool {
return assert.ErrorIs(t, err, ErrNonArchiveSource)
}
func removeTrustedCAs(client *http.Client) {
client.Transport.(*http.Transport).TLSClientConfig.RootCAs = x509.NewCertPool()
}
// createTarball makes a single-file tarball and returns it as a byte slice.
func createTarball(filename string, content []byte) []byte {
tarBuffer := new(bytes.Buffer)
tarWriter := tar.NewWriter(tarBuffer)
tarWriter.WriteHeader(&tar.Header{
Name: filename,
Size: int64(len(content)),
Mode: 0600,
})
tarWriter.Write(content)
tarWriter.Close()
return tarBuffer.Bytes()
}
type muxOption func(mux *http.ServeMux)
func withResponseForPath(t *testing.T, path string, response []byte) muxOption {
t.Helper()
return func(mux *http.ServeMux) {
mux.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
t.Logf("server handling request: %s %s", req.Method, req.URL)
_, err := w.Write(response)
if err != nil {
t.Fatal(err)
}
})
}
}
var testID = clio.Identification{
Name: "test-app",
Version: "v0.5.3",
}
func newTestServer(t *testing.T, muxOptions ...muxOption) *httptest.Server {
t.Helper()
mux := http.NewServeMux()
for _, option := range muxOptions {
option(mux)
}
server := httptest.NewTLSServer(mux)
t.Logf("new TLS server listening at %s", getHost(t, server))
return server
}
func createRequestURL(t *testing.T, server *httptest.Server, path string) string {
t.Helper()
// TODO: Figure out how to get this value from the server without hardcoding it here
const testServerCertificateName = "example.com"
serverURL, err := url.Parse(server.URL)
if err != nil {
t.Fatal(err)
}
// Set URL hostname to value from TLS certificate
serverURL.Host = fmt.Sprintf("%s:%s", testServerCertificateName, serverURL.Port())
serverURL.Path = path
return serverURL.String()
}
// getClient returns an http.Client that can be used to contact the test TLS server.
func getClient(t *testing.T, server *httptest.Server) *http.Client {
t.Helper()
httpClient := server.Client()
transport := httpClient.Transport.(*http.Transport)
serverHost := getHost(t, server)
transport.DialContext = func(_ context.Context, _, addr string) (net.Conn, error) {
t.Logf("client dialing %q for host %q", serverHost, addr)
// Ensure the client dials our test server
return net.Dial("tcp", serverHost)
}
return httpClient
}
// getHost extracts the host value from a server URL string.
// e.g. given a server with URL "http://1.2.3.4:5000/foo", getHost returns "1.2.3.4:5000"
func getHost(t *testing.T, server *httptest.Server) string {
t.Helper()
u, err := url.Parse(server.URL)
if err != nil {
t.Fatal(err)
}
return u.Hostname() + ":" + u.Port()
}
var testFileContent = []byte("This is the content of a test file!\n")
+89
View File
@@ -0,0 +1,89 @@
package file
import (
"errors"
"io/fs"
"os"
"path/filepath"
"github.com/diskfs/go-diskfs/filesystem"
)
type WalkDiskDirFunc func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error
// WalkDiskDir walks the file tree within the go-diskfs filesystem at root, calling fn for each file or directory in the tree, including root.
// This is meant to mimic the behavior of fs.WalkDir in the standard library.
func WalkDiskDir(fsys filesystem.FileSystem, root string, fn WalkDiskDirFunc) error {
infos, err := fsys.ReadDir(root)
if err != nil {
return err
}
if len(infos) == 0 {
return nil
}
for _, info := range infos {
p := filepath.Join(root, info.Name())
err = walkDiskDir(fsys, p, info, fn)
if err != nil {
if errors.Is(err, fs.SkipDir) {
continue
}
if errors.Is(err, fs.SkipAll) {
return nil
}
return err
}
}
return err
}
func walkDiskDir(fsys filesystem.FileSystem, name string, d os.FileInfo, walkDirFn WalkDiskDirFunc) error {
if err := walkDirFn(fsys, name, d, nil); err != nil {
if errors.Is(err, fs.SkipDir) && (d == nil || d.IsDir()) {
return nil
}
return err
}
isDir := d != nil && d.IsDir()
if d == nil {
_, err := fsys.ReadDir(name)
if err != nil {
return nil
}
isDir = true
}
if !isDir {
return nil
}
dirs, err := fsys.ReadDir(name)
if err != nil {
err = walkDirFn(fsys, name, d, err)
if err != nil {
if errors.Is(err, fs.SkipDir) {
return nil
}
return err
}
}
for _, d1 := range dirs {
name1 := filepath.Join(name, d1.Name())
if err := walkDiskDir(fsys, name1, d1, walkDirFn); err != nil {
if errors.Is(err, fs.SkipDir) {
break
}
if errors.Is(err, fs.SkipAll) {
return err
}
return err
}
}
return nil
}
+250
View File
@@ -0,0 +1,250 @@
package file
import (
"io/fs"
"os"
"path/filepath"
"testing"
"github.com/diskfs/go-diskfs/backend/file"
"github.com/diskfs/go-diskfs/filesystem"
"github.com/diskfs/go-diskfs/filesystem/squashfs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func createTestFS(t *testing.T) filesystem.FileSystem {
dir := t.TempDir()
filename := "test.squashfs"
f, err := os.Create(filepath.Join(dir, filename))
require.NoError(t, err)
b := file.New(f, false)
fsys, err := squashfs.Create(b, 0, 0, 4096)
require.NoError(t, err)
testFiles := []struct {
path string
content string
isDir bool
}{
{"/file1.txt", "content of file1", false},
{"/file2.txt", "content of file2", false},
{"/dir1", "", true},
{"/dir1/subfile1.txt", "content of subfile1", false},
{"/dir1/subfile2.txt", "content of subfile2", false},
{"/dir1/subdir1", "", true},
{"/dir1/subdir1/deepfile.txt", "deep content", false},
{"/dir2", "", true},
{"/dir2/anotherfile.txt", "another content", false},
{"/emptydir", "", true},
}
for _, tf := range testFiles {
if tf.isDir {
err := fsys.Mkdir(tf.path)
require.NoError(t, err)
} else {
f, err := fsys.OpenFile(tf.path, os.O_CREATE|os.O_RDWR)
require.NoError(t, err)
_, err = f.Write([]byte(tf.content))
require.NoError(t, err)
f.Close()
}
}
return fsys
}
func TestWalkDiskDir_CompleteTraversal(t *testing.T) {
fsys := createTestFS(t)
var visitedPaths []string
err := WalkDiskDir(fsys, "/", func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error {
require.NoError(t, err)
visitedPaths = append(visitedPaths, path)
return nil
})
require.NoError(t, err)
expectedPaths := []string{
"/file1.txt",
"/file2.txt",
"/dir1",
"/dir1/subfile1.txt",
"/dir1/subfile2.txt",
"/dir1/subdir1",
"/dir1/subdir1/deepfile.txt",
"/dir2",
"/dir2/anotherfile.txt",
"/emptydir",
}
assert.ElementsMatch(t, expectedPaths, visitedPaths)
}
func TestWalkDiskDir_FileInfoCorrect(t *testing.T) {
fsys := createTestFS(t)
var fileInfos []struct {
path string
isDir bool
name string
}
err := WalkDiskDir(fsys, "/", func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error {
require.NoError(t, err)
require.NotNil(t, d)
fileInfos = append(fileInfos, struct {
path string
isDir bool
name string
}{
path: path,
isDir: d.IsDir(),
name: d.Name(),
})
return nil
})
require.NoError(t, err)
for _, fi := range fileInfos {
expectedName := filepath.Base(fi.path)
assert.Equal(t, expectedName, fi.name)
if fi.path == "/dir1" || fi.path == "/dir2" || fi.path == "/emptydir" || fi.path == "/dir1/subdir1" {
assert.True(t, fi.isDir, "Expected %s to be directory", fi.path)
} else {
assert.False(t, fi.isDir, "Expected %s to be file", fi.path)
}
}
}
func TestWalkDiskDir_SkipDir(t *testing.T) {
fsys := createTestFS(t)
var visitedPaths []string
err := WalkDiskDir(fsys, "/", func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error {
require.NoError(t, err)
visitedPaths = append(visitedPaths, path)
if path == "/dir1" {
return fs.SkipDir
}
return nil
})
require.NoError(t, err)
assert.Contains(t, visitedPaths, "/dir1")
assert.NotContains(t, visitedPaths, "/dir1/subfile1.txt")
assert.NotContains(t, visitedPaths, "/dir1/subfile2.txt")
assert.NotContains(t, visitedPaths, "/dir1/subdir1")
assert.NotContains(t, visitedPaths, "/dir1/subdir1/deepfile.txt")
assert.Contains(t, visitedPaths, "/dir2")
assert.Contains(t, visitedPaths, "/dir2/anotherfile.txt")
}
func TestWalkDiskDir_SkipAll(t *testing.T) {
fsys := createTestFS(t)
var visitedPaths []string
err := WalkDiskDir(fsys, "/", func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error {
require.NoError(t, err)
visitedPaths = append(visitedPaths, path)
if path == "/dir1" {
return fs.SkipAll
}
return nil
})
require.NoError(t, err)
assert.Contains(t, visitedPaths, "/dir1")
assert.NotContains(t, visitedPaths, "/file1.txt")
assert.NotContains(t, visitedPaths, "/file2.txt")
assert.NotContains(t, visitedPaths, "/dir1/subfile1.txt")
assert.NotContains(t, visitedPaths, "/dir2")
assert.NotContains(t, visitedPaths, "/dir2/anotherfile.txt")
assert.NotContains(t, visitedPaths, "/emptydir")
}
func TestWalkDiskDir_EmptyDirectory(t *testing.T) {
fs := createTestFS(t)
var visitedPaths []string
err := WalkDiskDir(fs, "/emptydir", func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error {
require.NoError(t, err)
visitedPaths = append(visitedPaths, path)
return nil
})
require.NoError(t, err)
assert.Empty(t, visitedPaths)
}
func TestWalkDiskDir_NonexistentPath(t *testing.T) {
fs := createTestFS(t)
err := WalkDiskDir(fs, "/nonexistent", func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error {
return nil
})
assert.Error(t, err)
}
func TestWalkDiskDir_WalkFunctionError(t *testing.T) {
fs := createTestFS(t)
customErr := assert.AnError
err := WalkDiskDir(fs, "/", func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error {
if path == "/file1.txt" {
return customErr
}
return nil
})
assert.Error(t, err)
assert.Equal(t, customErr, err)
}
func TestWalkDiskDir_SubdirectoryTraversal(t *testing.T) {
fs := createTestFS(t)
var visitedPaths []string
err := WalkDiskDir(fs, "/dir1", func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error {
require.NoError(t, err)
visitedPaths = append(visitedPaths, path)
return nil
})
require.NoError(t, err)
expectedPaths := []string{
"/dir1/subfile1.txt",
"/dir1/subfile2.txt",
"/dir1/subdir1",
"/dir1/subdir1/deepfile.txt",
}
assert.ElementsMatch(t, expectedPaths, visitedPaths)
}
func TestWalkDiskDir_SingleFile(t *testing.T) {
fs := createTestFS(t)
var visitedPaths []string
err := WalkDiskDir(fs, "/file1.txt", func(fsys filesystem.FileSystem, path string, d os.FileInfo, err error) error {
require.NoError(t, err)
visitedPaths = append(visitedPaths, path)
return nil
})
// we are providing a file path, not a directory
require.Error(t, err)
assert.Empty(t, visitedPaths)
}
+61
View File
@@ -0,0 +1,61 @@
package os
import (
"context"
"fmt"
"regexp"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/sbomsync"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/sbom"
)
func DetectFeatures(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
builder.(sbomsync.Accessor).WriteToSBOM(func(s *sbom.SBOM) {
if s.Artifacts.LinuxDistribution == nil {
return
}
err := findRhelFeatures(resolver, s.Artifacts.LinuxDistribution)
if err != nil {
log.WithFields("error", err, "release", s.Artifacts.LinuxDistribution).Trace("error searching for extended support")
}
})
return nil
}
func findRhelFeatures(resolver file.Resolver, release *linux.Release) error {
if release == nil || release.ID != "rhel" {
return nil
}
contentManifestFiles, err := resolver.FilesByGlob("/root/buildinfo/content_manifests/*.json")
if err != nil {
return fmt.Errorf("unable to find content manifests: %w", err)
}
for _, contentManifestFile := range contentManifestFiles {
found, err := hasRhelExtendedSupportInContentManifest(resolver, contentManifestFile)
if err != nil {
return fmt.Errorf("unable to read content manifest from %s: %w", contentManifestFile.String(), err)
}
if found {
release.ExtendedSupport = true
break
}
}
return nil
}
func hasRhelExtendedSupportInContentManifest(resolver file.Resolver, contentManifestFile file.Location) (bool, error) {
contents, err := resolver.FileContentsByLocation(contentManifestFile)
if err != nil {
return false, fmt.Errorf("unable to read content manifest from %s: %w", contentManifestFile.String(), err)
}
defer internal.CloseAndLogError(contents, "content-manifest")
patterns := []*regexp.Regexp{regexp.MustCompile(`baseos-eus`), regexp.MustCompile(`baseos-eus|appstream-eus`)}
return internal.MatchAnyFromReader(contents, patterns...)
}
+97
View File
@@ -0,0 +1,97 @@
package os_test
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/internal/os"
"github.com/anchore/syft/internal/sbomsync"
"github.com/anchore/syft/internal/task"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
)
func Test_EnvironmentTask(t *testing.T) {
tests := []struct {
name string
expected linux.Release
}{
{
name: "not_rhel",
expected: linux.Release{
PrettyName: "Red Hat Enterprise Linux 9.4 (Plow)",
Name: "Red Hat Enterprise Linux",
ID: "not-rhel",
IDLike: []string{
"fedora",
},
Version: "9.4 (Plow)",
VersionID: "9.4",
HomeURL: "https://www.redhat.com/",
BugReportURL: "https://issues.redhat.com/",
CPEName: "cpe:/o:redhat:enterprise_linux:9::baseos",
ExtendedSupport: false, // important
},
},
{
name: "rhel_content_manifests",
expected: linux.Release{
PrettyName: "Red Hat Enterprise Linux 9.4 (Plow)",
Name: "Red Hat Enterprise Linux",
ID: "rhel",
IDLike: []string{
"fedora",
},
Version: "9.4 (Plow)",
VersionID: "9.4",
HomeURL: "https://www.redhat.com/",
BugReportURL: "https://issues.redhat.com/",
CPEName: "cpe:/o:redhat:enterprise_linux:9::baseos",
ExtendedSupport: true, // important
},
},
{
name: "rhel_no_manifests",
expected: linux.Release{
PrettyName: "Red Hat Enterprise Linux 9.4 (Plow)",
Name: "Red Hat Enterprise Linux",
ID: "rhel",
IDLike: []string{
"fedora",
},
Version: "9.4 (Plow)",
VersionID: "9.4",
HomeURL: "https://www.redhat.com/",
BugReportURL: "https://issues.redhat.com/",
CPEName: "cpe:/o:redhat:enterprise_linux:9::baseos",
ExtendedSupport: false, // important
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
tarPath := imagetest.GetFixtureImageTarPath(t, test.name)
// get the source
theSource, err := syft.GetSource(context.Background(), tarPath, syft.DefaultGetSourceConfig().WithSources("docker-archive"))
require.NoError(t, err)
resolver, err := theSource.FileResolver(source.SquashedScope)
require.NoError(t, err)
s := sbom.SBOM{}
err = task.NewEnvironmentTask().Execute(context.Background(), resolver, sbomsync.NewBuilder(&s))
require.NoError(t, err)
err = os.DetectFeatures(context.Background(), resolver, sbomsync.NewBuilder(&s))
require.NoError(t, err)
require.Equal(t, &test.expected, s.Artifacts.LinuxDistribution)
})
}
}
@@ -0,0 +1,4 @@
FROM scratch
COPY etc/os-release /etc/
COPY root/buildinfo/content_manifests/*.json /root/buildinfo/content_manifests/
@@ -0,0 +1,18 @@
NAME="Red Hat Enterprise Linux"
VERSION="9.4 (Plow)"
ID="not-rhel"
ID_LIKE="fedora"
VERSION_ID="9.4"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Red Hat Enterprise Linux 9.4 (Plow)"
ANSI_COLOR="0;31"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:redhat:enterprise_linux:9::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9"
BUG_REPORT_URL="https://issues.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 9"
REDHAT_BUGZILLA_PRODUCT_VERSION=9.4
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="9.4"
@@ -0,0 +1,14 @@
{
"image_contents": [],
"metadata": {
"icm_spec": "https://raw.githubusercontent.com/containerbuildsystem/atomic-reactor/f4abcfdaf8247a6b074f94fa84f3846f82d781c6/atomic_reactor/schemas/content_manifest.json",
"icm_version": 1,
"image_layer_index": 3
},
"content_sets": [
"rhel-9-for-x86_64-appstream-eus-rpms__9_DOT_4",
"rhel-9-for-x86_64-baseos-eus-rpms__9_DOT_4",
"rhel-9-for-x86_64-rt-rpms__9_DOT_4",
"rhocp-4.16-for-rhel-9-x86_64-rpms"
]
}
@@ -0,0 +1,4 @@
FROM scratch
COPY etc/os-release /etc/
COPY root/buildinfo/content_manifests/*.json /root/buildinfo/content_manifests/
@@ -0,0 +1,18 @@
NAME="Red Hat Enterprise Linux"
VERSION="9.4 (Plow)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="9.4"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Red Hat Enterprise Linux 9.4 (Plow)"
ANSI_COLOR="0;31"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:redhat:enterprise_linux:9::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9"
BUG_REPORT_URL="https://issues.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 9"
REDHAT_BUGZILLA_PRODUCT_VERSION=9.4
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="9.4"
@@ -0,0 +1,14 @@
{
"image_contents": [],
"metadata": {
"icm_spec": "https://raw.githubusercontent.com/containerbuildsystem/atomic-reactor/f4abcfdaf8247a6b074f94fa84f3846f82d781c6/atomic_reactor/schemas/content_manifest.json",
"icm_version": 1,
"image_layer_index": 3
},
"content_sets": [
"rhel-9-for-x86_64-appstream-eus-rpms__9_DOT_4",
"rhel-9-for-x86_64-baseos-eus-rpms__9_DOT_4",
"rhel-9-for-x86_64-rt-rpms__9_DOT_4",
"rhocp-4.16-for-rhel-9-x86_64-rpms"
]
}
@@ -0,0 +1,13 @@
{
"image_contents": [],
"metadata": {
"icm_spec": "https://raw.githubusercontent.com/containerbuildsystem/atomic-reactor/f4abcfdaf8247a6b074f94fa84f3846f82d781c6/atomic_reactor/schemas/content_manifest.json",
"icm_version": 1,
"image_layer_index": 1
},
"content_sets": [
"rhel-9-for-x86_64-appstream-eus-rpms__9_DOT_4",
"rhel-9-for-x86_64-baseos-eus-rpms__9_DOT_4",
"rhocp-4.16-for-rhel-9-x86_64-rpms"
]
}
@@ -0,0 +1,3 @@
FROM scratch
COPY ./etc/os-release /etc/
@@ -0,0 +1,18 @@
NAME="Red Hat Enterprise Linux"
VERSION="9.4 (Plow)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="9.4"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Red Hat Enterprise Linux 9.4 (Plow)"
ANSI_COLOR="0;31"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:redhat:enterprise_linux:9::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9"
BUG_REPORT_URL="https://issues.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 9"
REDHAT_BUGZILLA_PRODUCT_VERSION=9.4
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="9.4"
+2 -2
View File
@@ -41,11 +41,11 @@ func MatchNamedCaptureGroups(regEx *regexp.Regexp, content string) map[string]st
// 1.5x the reader chunk size (1MB * 1.5).
func MatchNamedCaptureGroupsFromReader(re *regexp.Regexp, r io.Reader) (map[string]string, error) {
results := make(map[string]string)
_, err := processReaderInChunks(r, readerChunkSize, matchNamedCaptureGroupsHandler(re, results))
matches, err := processReaderInChunks(r, readerChunkSize, matchNamedCaptureGroupsHandler(re, results))
if err != nil {
return nil, err
}
if len(results) == 0 {
if !matches {
return nil, nil
}
return results, nil
+63 -6
View File
@@ -92,6 +92,12 @@ func findOwnershipByFilesRelationships(resolver file.Resolver, catalog *pkg.Coll
return relationships
}
// Build a map of real paths to packages that directly own them. We'll use this
// to check if a file is already owned by the same type of package when we're
// determining ownership via symlink.
directOwnership := directOwnersByPath(catalog)
// Now establish relationships, considering symlinks
for _, candidateOwnerPkg := range catalog.Sorted() {
id := candidateOwnerPkg.ID()
if candidateOwnerPkg.Metadata == nil {
@@ -105,16 +111,34 @@ func findOwnershipByFilesRelationships(resolver file.Resolver, catalog *pkg.Coll
}
for _, ownedFilePath := range pkgFileOwner.OwnedFiles() {
// find the first path that results in a hit
for _, ownedPath := range allPaths(ownedFilePath, resolver) {
if matchesAny(ownedPath, globsForbiddenFromBeingOwned) {
if ownedFilePath == "" {
continue
}
// find paths that result in a hit (includes resolving symlinks)
resolvedPaths := resolvePaths(ownedFilePath, resolver)
for _, resolvedPath := range resolvedPaths {
if matchesAny(resolvedPath, globsForbiddenFromBeingOwned) {
// we skip over known exceptions to file ownership, such as the RPM package owning
// the RPM DB path, otherwise the RPM package would "own" all RPMs, which is not intended
continue
}
// Skip claiming ownership via symlink if another package of the same type
// directly owns this real path. This is the specific fix for the issue where a
// symlink shouldn't allow a package to claim ownership when another package of
// the same type directly owns the real file.
if resolvedPath != ownedFilePath { // This is a resolved symlink path
// Check if another package of the same type directly owns this path
if paths := directOwnership[candidateOwnerPkg.Type]; paths != nil && paths.Has(resolvedPath) {
// Skip this path - a package of the same type directly owns it
continue
}
}
// look for package(s) in the catalog that may be owned by this package and mark the relationship
for _, subPackage := range catalog.PackagesByPath(ownedPath) {
for _, subPackage := range catalog.PackagesByPath(resolvedPath) {
subID := subPackage.ID()
if subID == id {
continue
@@ -126,7 +150,7 @@ func findOwnershipByFilesRelationships(resolver file.Resolver, catalog *pkg.Coll
if _, exists := relationships[id][subID]; !exists {
relationships[id][subID] = strset.New()
}
relationships[id][subID].Add(ownedPath)
relationships[id][subID].Add(resolvedPath)
}
}
}
@@ -135,7 +159,40 @@ func findOwnershipByFilesRelationships(resolver file.Resolver, catalog *pkg.Coll
return relationships
}
func allPaths(ownedFilePath string, resolver file.Resolver) []string {
func directOwnersByPath(catalog *pkg.Collection) map[pkg.Type]*strset.Set {
directOwnership := map[pkg.Type]*strset.Set{}
// First, identify direct ownership of all files
for _, p := range catalog.Sorted() {
if p.Metadata == nil {
continue
}
// check to see if this is a file owner
pkgFileOwner, ok := p.Metadata.(pkg.FileOwner)
if !ok {
continue
}
for _, ownedFilePath := range pkgFileOwner.OwnedFiles() {
if ownedFilePath == "" {
continue
}
// Register direct ownership
paths := directOwnership[p.Type]
if paths == nil {
paths = strset.New()
directOwnership[p.Type] = paths
}
paths.Add(ownedFilePath)
}
}
return directOwnership
}
func resolvePaths(ownedFilePath string, resolver file.Resolver) []string {
// though we have a string path, we need to resolve symlinks and other filesystem oddities since we cannot assume this is a real path
var locs []file.Location
var err error
@@ -78,6 +78,64 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
return []pkg.Package{parent, child}, []artifact.Relationship{relationship}
},
},
{
name: "only-real-file-owner-gets-ownership-relationship-not-symlink-owner",
resolver: mockFR{
translate: map[string]string{
"/usr/bin/jenkins.war-symlink": "/usr/share/jenkins/jenkins.war", // symlink to the real file
},
},
setup: func(t testing.TB) ([]pkg.Package, []artifact.Relationship) {
// Package that owns the symlink
symlinkOwner := pkg.Package{
Type: pkg.ApkPkg,
Metadata: pkg.ApkDBEntry{
Package: "jenkins-symlink-pkg",
Files: []pkg.ApkFileRecord{
{Path: "/usr/bin/jenkins.war-symlink"}, // this symlinks to the real file
},
},
}
symlinkOwner.SetID()
// Package that owns the real file
realFileOwner := pkg.Package{
Type: pkg.ApkPkg,
Metadata: pkg.ApkDBEntry{
Package: "jenkins-real-pkg",
Files: []pkg.ApkFileRecord{
{Path: "/usr/share/jenkins/jenkins.war"}, // the real file
},
},
}
realFileOwner.SetID()
// A third package that is "located at" the real file path
// This simulates a package being discovered at the jenkins.war location
consumerPackage := pkg.Package{
Type: pkg.JavaPkg,
Locations: file.NewLocationSet(
file.NewVirtualLocation("/usr/share/jenkins/jenkins.war", "/usr/share/jenkins/jenkins.war"),
),
}
consumerPackage.SetID()
// Only the real file owner should have an ownership relationship with the consumer package
// The symlink owner should NOT have a relationship with the consumer
relationship := artifact.Relationship{
From: realFileOwner,
To: consumerPackage,
Type: artifact.OwnershipByFileOverlapRelationship,
Data: ownershipByFilesMetadata{
Files: []string{
"/usr/share/jenkins/jenkins.war",
},
},
}
return []pkg.Package{symlinkOwner, realFileOwner, consumerPackage}, []artifact.Relationship{relationship}
},
},
{
name: "misses-by-dead-symlink",
resolver: mockFR{
+11
View File
@@ -13,6 +13,17 @@ func HasAnyOfPrefixes(input string, prefixes ...string) bool {
return false
}
// HasAnyOfSuffixes returns an indication if the given string has any of the given suffixes.
func HasAnyOfSuffixes(input string, suffixes ...string) bool {
for _, suffix := range suffixes {
if strings.HasSuffix(input, suffix) {
return true
}
}
return false
}
func TruncateMiddleEllipsis(input string, maxLen int) string {
if len(input) <= maxLen {
return input
+57
View File
@@ -7,6 +7,63 @@ import (
"github.com/stretchr/testify/assert"
)
func TestHasAnyOfSuffixes(t *testing.T) {
tests := []struct {
name string
input string
suffixes []string
expected bool
}{
{
name: "go case",
input: "this has something",
suffixes: []string{
"has something",
"has NOT something",
},
expected: true,
},
{
name: "no match",
input: "this has something",
suffixes: []string{
"has NOT something",
},
expected: false,
},
{
name: "empty",
input: "this has something",
suffixes: []string{},
expected: false,
},
{
name: "positive match last",
input: "this has something",
suffixes: []string{
"that does not have",
"something",
},
expected: true,
},
{
name: "empty input",
input: "",
suffixes: []string{
"that does not have",
"this has",
},
expected: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expected, HasAnyOfSuffixes(test.input, test.suffixes...))
})
}
}
func TestHasAnyOfPrefixes(t *testing.T) {
tests := []struct {
name string
+1 -1
View File
@@ -15,7 +15,7 @@ import (
"github.com/anchore/syft/syft/sbom"
)
func RunTask(ctx context.Context, tsk Task, resolver file.Resolver, s sbomsync.Builder, prog *monitor.CatalogerTaskProgress) error {
func RunTask(ctx context.Context, tsk Task, resolver file.Resolver, s sbomsync.Builder, prog *monitor.TaskProgress) error {
err := runTaskSafely(ctx, tsk, resolver, s)
unknowns, remainingErrors := unknown.ExtractCoordinateErrors(err)
if len(unknowns) > 0 {
+1 -1
View File
@@ -17,7 +17,7 @@ func Test_TaskExecutor_PanicHandling(t *testing.T) {
panic("something bad happened")
})
err := RunTask(context.Background(), tsk, nil, nil, &monitor.CatalogerTaskProgress{
err := RunTask(context.Background(), tsk, nil, nil, &monitor.TaskProgress{
Manual: progress.NewManual(-1),
})
+7
View File
@@ -0,0 +1,7 @@
package task
import "github.com/anchore/syft/internal/os"
func NewOSFeatureDetectionTask() Task {
return NewTask("os-feature-detection", os.DetectFeatures)
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+73 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "anchore.io/schema/syft/json/16.0.34/document",
"$id": "anchore.io/schema/syft/json/16.0.36/document",
"$ref": "#/$defs/Document",
"$defs": {
"AlpmDbEntry": {
@@ -1628,6 +1628,9 @@
},
"supportEnd": {
"type": "string"
},
"extendedSupport": {
"type": "boolean"
}
},
"type": "object"
@@ -2001,6 +2004,9 @@
{
"$ref": "#/$defs/PythonPoetryLockEntry"
},
{
"$ref": "#/$defs/PythonUvLockEntry"
},
{
"$ref": "#/$defs/RDescription"
},
@@ -2594,6 +2600,72 @@
"dependencies"
]
},
"PythonUvLockDependencyEntry": {
"properties": {
"name": {
"type": "string"
},
"optional": {
"type": "boolean"
},
"markers": {
"type": "string"
},
"extras": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object",
"required": [
"name",
"optional"
]
},
"PythonUvLockEntry": {
"properties": {
"index": {
"type": "string"
},
"dependencies": {
"items": {
"$ref": "#/$defs/PythonUvLockDependencyEntry"
},
"type": "array"
},
"extras": {
"items": {
"$ref": "#/$defs/PythonUvLockExtraEntry"
},
"type": "array"
}
},
"type": "object",
"required": [
"index",
"dependencies"
]
},
"PythonUvLockExtraEntry": {
"properties": {
"name": {
"type": "string"
},
"dependencies": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object",
"required": [
"name",
"dependencies"
]
},
"RDescription": {
"properties": {
"title": {
+3 -3
View File
@@ -144,14 +144,14 @@ func setContextExecutors(ctx context.Context, cfg *CreateSBOMConfig) context.Con
return ctx
}
func monitorPackageCount(prog *monitor.CatalogerTaskProgress) func(s *sbom.SBOM) {
func monitorPackageCount(prog *monitor.TaskProgress) func(s *sbom.SBOM) {
return func(s *sbom.SBOM) {
count := humanize.Comma(int64(s.Artifacts.Packages.PackageCount()))
prog.AtomicStage.Set(fmt.Sprintf("%s packages", count))
}
}
func monitorPackageCatalogingTask() *monitor.CatalogerTaskProgress {
func monitorPackageCatalogingTask() *monitor.TaskProgress {
info := monitor.GenericTask{
Title: monitor.Title{
Default: "Packages",
@@ -164,7 +164,7 @@ func monitorPackageCatalogingTask() *monitor.CatalogerTaskProgress {
return bus.StartCatalogerTask(info, -1, "")
}
func monitorCatalogingTask(srcID artifact.ID, tasks [][]task.Task) *monitor.CatalogerTaskProgress {
func monitorCatalogingTask(srcID artifact.ID, tasks [][]task.Task) *monitor.TaskProgress {
info := monitor.GenericTask{
Title: monitor.Title{
Default: "Catalog contents",
+19
View File
@@ -191,6 +191,7 @@ func (c *CreateSBOMConfig) makeTaskGroups(src source.Description) ([][]task.Task
scopeTasks := c.scopeTasks()
relationshipsTasks := c.relationshipTasks(src)
unknownTasks := c.unknownsTasks()
osFeatureDetectionTasks := c.osFeatureDetectionTasks()
pkgTasks, fileTasks, selectionEvidence, err := c.selectTasks(src)
if err != nil {
@@ -220,6 +221,11 @@ func (c *CreateSBOMConfig) makeTaskGroups(src source.Description) ([][]task.Task
taskGroups = append(taskGroups, unknownTasks)
}
// osFeatureDetectionTasks should happen after package scanning is complete
if len(osFeatureDetectionTasks) > 0 {
taskGroups = append(taskGroups, osFeatureDetectionTasks)
}
// identifying the environment (i.e. the linux release) must be done first as this is required for package cataloging
taskGroups = append(
[][]task.Task{
@@ -444,6 +450,17 @@ func (c *CreateSBOMConfig) unknownsTasks() []task.Task {
return tasks
}
// osFeatureDetectionTasks returns a set of tasks that perform post-processing feature detection and update the SBOM accordingly
func (c *CreateSBOMConfig) osFeatureDetectionTasks() []task.Task {
var tasks []task.Task
if t := task.NewOSFeatureDetectionTask(); t != nil {
tasks = append(tasks, t)
}
return tasks
}
func (c *CreateSBOMConfig) validate() error {
if c.Relationships.ExcludeBinaryPackagesWithFileOwnershipOverlap {
if !c.Relationships.PackageFileOwnershipOverlap {
@@ -464,6 +481,8 @@ func findDefaultTags(src source.Description) ([]string, error) {
return []string{pkgcataloging.ImageTag, filecataloging.FileTag}, nil
case source.FileMetadata, source.DirectoryMetadata:
return []string{pkgcataloging.DirectoryTag, filecataloging.FileTag}, nil
case source.SnapMetadata:
return []string{pkgcataloging.InstalledTag, filecataloging.FileTag}, nil
default:
return nil, fmt.Errorf("unable to determine default cataloger tag for source type=%T", m)
}
+15
View File
@@ -91,6 +91,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
fileCatalogerNames(),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -110,6 +111,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
fileCatalogerNames(),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -130,6 +132,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
fileCatalogerNames(),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -149,6 +152,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
fileCatalogerNames("file-metadata", "content", "binary-metadata"),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -169,6 +173,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
nil, // note: there is a file cataloging group, with no items in it
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -192,6 +197,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -213,6 +219,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
fileCatalogerNames(),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -234,6 +241,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
fileCatalogerNames(),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -255,6 +263,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
fileCatalogerNames(),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -277,6 +286,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
fileCatalogerNames(),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -298,6 +308,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
fileCatalogerNames(),
relationshipCatalogerNames(),
unknownsTaskNames(),
osFeatureDetectionTaskNames(),
},
wantManifest: &catalogerManifest{
Requested: cataloging.SelectionRequest{
@@ -430,6 +441,10 @@ func unknownsTaskNames() []string {
return []string{"unknowns-labeler"}
}
func osFeatureDetectionTaskNames() []string {
return []string{"os-feature-detection"}
}
func environmentCatalogerNames() []string {
return []string{"environment-cataloger"}
}
+4
View File
@@ -23,6 +23,10 @@ const (
// CatalogerTaskStarted is a partybus event that occurs when starting a task within a cataloger
CatalogerTaskStarted partybus.EventType = typePrefix + "-cataloger-task-started"
// PullSourceStarted is a partybus event that occurs when starting to pull a source (does not overlap with stereoscope image pull events,
// this covers any additional sources such as snap and git repos).
PullSourceStarted partybus.EventType = typePrefix + "-pull-source-started"
// Events exclusively for the CLI
// CLIAppUpdateAvailable is a partybus event that occurs when an application update is available
@@ -1,15 +0,0 @@
package monitor
import (
"github.com/wagoodman/go-progress"
)
const (
TopLevelCatalogingTaskID = "cataloging"
PackageCatalogingTaskID = "package-cataloging"
)
type CatalogerTaskProgress struct {
*progress.AtomicStage
*progress.Manual
}
+10
View File
@@ -6,6 +6,11 @@ import (
"github.com/wagoodman/go-progress"
)
const (
TopLevelCatalogingTaskID = "cataloging"
PackageCatalogingTaskID = "package-cataloging"
)
type ShellProgress struct {
io.Reader
progress.Progressable
@@ -34,3 +39,8 @@ type GenericTask struct {
ParentID string
Context string
}
type TaskProgress struct {
*progress.AtomicStage
*progress.Manual
}
+20
View File
@@ -77,6 +77,26 @@ func ParseCatalogerTaskStarted(e partybus.Event) (progress.StagedProgressable, *
return mon, &source, nil
}
func ParsePullSourceStarted(e partybus.Event) (progress.StagedProgressable, *monitor.GenericTask, error) {
if err := checkEventType(e.Type, event.PullSourceStarted); err != nil {
return nil, nil, err
}
var mon progress.StagedProgressable
source, ok := e.Source.(monitor.GenericTask)
if !ok {
return nil, nil, newPayloadErr(e.Type, "Source", e.Source)
}
mon, ok = e.Value.(progress.StagedProgressable)
if !ok {
mon = nil
}
return mon, &source, nil
}
func ParseAttestationStartedEvent(e partybus.Event) (io.Reader, progress.Progressable, *monitor.GenericTask, error) {
if err := checkEventType(e.Type, event.AttestationStarted); err != nil {
return nil, nil, nil, err
+1 -1
View File
@@ -106,7 +106,7 @@ func processExecutableLocation(loc file.Location, resolver file.Resolver) (*file
return processExecutable(loc, uReader)
}
func catalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
func catalogingProgress(locations int64) *monitor.TaskProgress {
info := monitor.GenericTask{
Title: monitor.Title{
Default: "Executables",
+1 -1
View File
@@ -113,7 +113,7 @@ func (i *Cataloger) catalogLocation(resolver file.Resolver, location file.Locati
return buf.String(), nil
}
func catalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
func catalogingProgress(locations int64) *monitor.TaskProgress {
info := monitor.GenericTask{
Title: monitor.Title{
Default: "File contents",
+1 -1
View File
@@ -112,7 +112,7 @@ func (i *Cataloger) catalogLocation(ctx context.Context, resolver file.Resolver,
return digests, nil
}
func catalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
func catalogingProgress(locations int64) *monitor.TaskProgress {
info := monitor.GenericTask{
Title: monitor.Title{
Default: "File digests",
@@ -76,7 +76,7 @@ func (i *Cataloger) Catalog(ctx context.Context, resolver file.Resolver, coordin
return results, errs
}
func catalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
func catalogingProgress(locations int64) *monitor.TaskProgress {
info := monitor.GenericTask{
Title: monitor.Title{
Default: "File metadata",
@@ -480,6 +480,10 @@ func Test_toOsComponent(t *testing.T) {
Version: "myVersion",
},
Properties: &[]cyclonedx.Property{
{
Name: "syft:distro:extendedSupport",
Value: "false",
},
{
Name: "syft:distro:id",
Value: "myLinux",
@@ -37,6 +37,7 @@ const (
prefixImage = "Image"
prefixDirectory = "Directory"
prefixFile = "File"
prefixSnap = "Snap"
prefixUnknown = "Unknown"
)
@@ -228,6 +229,18 @@ func toRootPackage(s source.Description) *spdx.Package {
Value: d.Value,
})
}
case source.SnapMetadata:
prefix = prefixSnap
purpose = spdxPrimaryPurposeContainer
for _, d := range m.Digests {
checksums = append(checksums, spdx.Checksum{
Algorithm: toChecksumAlgorithm(d.Algorithm),
Value: d.Value,
})
}
default:
prefix = prefixUnknown
purpose = spdxPrimaryPurposeOther
@@ -237,6 +237,82 @@ func Test_toFormatModel(t *testing.T) {
},
},
},
{
name: "snap",
in: sbom.SBOM{
Source: source.Description{
Name: "etcd",
Version: "3.4.36",
Metadata: source.SnapMetadata{
Summary: "Distributed reliable key-value store",
Base: "core18",
Grade: "stable",
Confinement: "strict",
Architectures: []string{
"amd64",
},
Digests: []file.Digest{
{
Algorithm: "sha256",
Value: "d34db33f",
},
},
},
},
Artifacts: sbom.Artifacts{
Packages: pkg.NewCollection(pkg.Package{
Name: "pkg-1",
Version: "version-1",
}),
},
},
expected: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
SPDXVersion: spdx.Version,
DataLicense: spdx.DataLicense,
DocumentName: "etcd",
Packages: []*spdx.Package{
{
PackageSPDXIdentifier: "Package-pkg-1-pkg-1",
PackageName: "pkg-1",
PackageVersion: "version-1",
PackageSupplier: &spdx.Supplier{
Supplier: "NOASSERTION",
},
},
{
PackageSPDXIdentifier: "DocumentRoot-Snap-etcd",
PackageName: "etcd",
PackageVersion: "3.4.36",
PrimaryPackagePurpose: "CONTAINER",
PackageChecksums: []spdx.Checksum{{Algorithm: "SHA256", Value: "d34db33f"}},
PackageSupplier: &spdx.Supplier{
Supplier: "NOASSERTION",
},
},
},
Relationships: []*spdx.Relationship{
{
RefA: spdx.DocElementID{
ElementRefID: "DocumentRoot-Snap-etcd",
},
RefB: spdx.DocElementID{
ElementRefID: "Package-pkg-1-pkg-1",
},
Relationship: spdx.RelationshipContains,
},
{
RefA: spdx.DocElementID{
ElementRefID: "DOCUMENT",
},
RefB: spdx.DocElementID{
ElementRefID: "DocumentRoot-Snap-etcd",
},
Relationship: spdx.RelationshipDescribes,
},
},
},
},
}
for _, test := range tests {
@@ -10,6 +10,7 @@ import (
"strconv"
"strings"
"github.com/scylladb/go-set/strset"
"github.com/spdx/tools-golang/spdx"
"github.com/spdx/tools-golang/spdx/v2/common"
@@ -45,7 +46,7 @@ func ToSyftModel(doc *spdx.Document) (*sbom.SBOM, error) {
},
}
collectSyftPackages(s, spdxIDMap, doc.Packages)
collectSyftPackages(s, spdxIDMap, doc)
collectSyftFiles(s, spdxIDMap, doc)
@@ -279,8 +280,12 @@ func findLinuxReleaseByPURL(doc *spdx.Document) *linux.Release {
return nil
}
func collectSyftPackages(s *sbom.SBOM, spdxIDMap map[string]any, packages []*spdx.Package) {
for _, p := range packages {
func collectSyftPackages(s *sbom.SBOM, spdxIDMap map[string]any, doc *spdx.Document) {
skipIDs := packageIDsToSkip(doc)
for _, p := range doc.Packages {
if p == nil || skipIDs.Has(string(p.PackageSPDXIdentifier)) {
continue
}
syftPkg := toSyftPackage(p)
spdxIDMap[string(p.PackageSPDXIdentifier)] = syftPkg
s.Artifacts.Packages.Add(syftPkg)
@@ -657,3 +662,15 @@ func extractCPEs(p *spdx.Package) (cpes []cpe.CPE) {
}
return cpes
}
// packageIDsToSkip returns a set of packageIDs that should not be imported
func packageIDsToSkip(doc *spdx.Document) *strset.Set {
skipIDs := strset.New()
for i := 0; i < len(doc.Relationships); i++ {
r := doc.Relationships[i]
if r != nil && r.Relationship == spdx.RelationshipGeneratedFrom {
skipIDs.Add(string(r.RefB.ElementRefID))
}
}
return skipIDs
}
@@ -759,3 +759,37 @@ func Test_useSPDXIdentifierOverDerivedSyftArtifactID(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, s.Artifacts.Packages.Package("1"))
}
func Test_skipsPackagesWithGeneratedFromRelationship(t *testing.T) {
doc := &spdx.Document{
SPDXVersion: "SPDX-2.3",
Packages: []*spdx.Package{
{
PackageName: "package-1",
PackageSPDXIdentifier: "1",
PackageVersion: "1.0.5",
},
{
PackageName: "package-1-src",
PackageSPDXIdentifier: "1-src",
PackageVersion: "1.0.5-src",
},
},
Relationships: []*spdx.Relationship{
{
Relationship: spdx.RelationshipGeneratedFrom,
RefA: common.DocElementID{ // package 1
ElementRefID: spdx.ElementID("1"),
},
RefB: common.DocElementID{ // generated from package 1-src
ElementRefID: spdx.ElementID("1-src"),
},
},
},
}
s, err := ToSyftModel(doc)
assert.Nil(t, err)
assert.NotNil(t, s.Artifacts.Packages.Package("1"))
assert.Nil(t, s.Artifacts.Packages.Package("1-src"))
}
@@ -102,6 +102,10 @@
"version": "1.2.3"
},
"properties": [
{
"name": "syft:distro:extendedSupport",
"value": "false"
},
{
"name": "syft:distro:id",
"value": "debian"
@@ -111,6 +111,10 @@
"version": "1.2.3"
},
"properties": [
{
"name": "syft:distro:extendedSupport",
"value": "false"
},
{
"name": "syft:distro:id",
"value": "debian"
@@ -53,6 +53,7 @@
<description>debian</description>
<swid tagId="debian" name="debian" version="1.2.3"></swid>
<properties>
<property name="syft:distro:extendedSupport">false</property>
<property name="syft:distro:id">debian</property>
<property name="syft:distro:idLike:0">like!</property>
<property name="syft:distro:prettyName">debian</property>
@@ -11,7 +11,7 @@
</component>
</components>
</tools>
<component bom-ref="f28a4ba3ddfdddad" type="container">
<component bom-ref="redacted" type="container">
<name>user-image-input</name>
<version>sha256:redacted</version>
</component>
@@ -56,6 +56,7 @@
<description>debian</description>
<swid tagId="debian" name="debian" version="1.2.3"></swid>
<properties>
<property name="syft:distro:extendedSupport">false</property>
<property name="syft:distro:id">debian</property>
<property name="syft:distro:idLike:0">like!</property>
<property name="syft:distro:prettyName">debian</property>
@@ -130,6 +130,11 @@ func toPath(s source.Description, p pkg.Package) string {
return fmt.Sprintf("%s/%s", path, packagePath)
}
return packagePath
case source.SnapMetadata:
if inputPath != "" {
return fmt.Sprintf("%s:/%s", inputPath, packagePath)
}
return packagePath
}
}
return inputPath
@@ -173,6 +173,11 @@ func Test_toGithubModel(t *testing.T) {
metadata: source.FileMetadata{Path: "./archive.tar.gz"},
testPath: "archive.tar.gz:/etc",
},
{
name: "snap",
metadata: source.SnapMetadata{},
testPath: "name:/etc",
},
}
for _, test := range tests {
@@ -180,6 +185,7 @@ func Test_toGithubModel(t *testing.T) {
s := sbomFixture()
if test.metadata != nil {
s.Source.Name = "name"
s.Source.Metadata = test.metadata
}
actual := ToGithubModel(&s)
@@ -45,6 +45,15 @@ func Test_DocumentName(t *testing.T) {
},
expected: "some/path/to/place",
},
{
name: "snap",
srcMetadata: source.Description{
Name: "some/name",
// there is nothing in the snap metadata that indicates a name
Metadata: source.SnapMetadata{},
},
expected: "some/name",
},
{
name: "named",
srcMetadata: source.Description{
@@ -16,6 +16,7 @@ const (
InputImage = "image"
InputDirectory = "dir"
InputFile = "file"
InputSnap = "snap"
)
func DocumentNameAndNamespace(src source.Description, desc sbom.Descriptor) (string, string) {
@@ -33,6 +34,8 @@ func DocumentNamespace(name string, src source.Description, desc sbom.Descriptor
input = InputDirectory
case source.FileMetadata:
input = InputFile
case source.SnapMetadata:
input = InputSnap
}
uniqueID := uuid.Must(uuid.NewRandom())
@@ -12,7 +12,7 @@ import (
"github.com/anchore/syft/syft/source"
)
func Test_documentNamespace(t *testing.T) {
func Test_DocumentNamespace(t *testing.T) {
tracker := sourcemetadata.NewCompletionTester(t)
tests := []struct {
@@ -53,6 +53,14 @@ func Test_documentNamespace(t *testing.T) {
},
expected: "https://anchore.com/syft/file/my-name-",
},
{
name: "snap",
inputName: "my-name",
src: source.Description{
Metadata: source.SnapMetadata{},
},
expected: "https://anchore.com/syft/snap/my-name-",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
@@ -42,6 +42,7 @@ func Test_OriginatorSupplier(t *testing.T) {
pkg.PythonPipfileLockEntry{},
pkg.PythonRequirementsEntry{},
pkg.PythonPoetryLockEntry{},
pkg.PythonUvLockEntry{},
pkg.RustBinaryAuditEntry{},
pkg.RustCargoLockEntry{},
pkg.SwiftPackageManagerResolvedEntry{},
+4 -4
View File
@@ -68,15 +68,15 @@ func AssertEncoderAgainstGoldenSnapshot(t *testing.T, cfg EncoderSnapshotTestCon
if cfg.IsJSON {
require.JSONEq(t, string(expected), string(actual))
} else {
requireEqual(t, expected, actual)
requireEqual(t, string(expected), string(actual))
}
}
func requireEqual(t *testing.T, expected any, actual any) {
func requireEqual(t *testing.T, expected string, actual string) {
if diff := cmp.Diff(expected, actual); diff != "" {
// uncomment to debug
// t.Logf("expected: %s", expected)
// t.Logf("actual: %s", actual)
// t.Logf("expected:\n%s", expected)
// t.Logf("actual:\n%s", actual)
t.Fatalf("mismatched output: %s", diff)
}
}
+2 -2
View File
@@ -114,12 +114,12 @@ func TestOutOfDateParser(t *testing.T) {
name: "warning when document version is unparseable",
documentVersion: "some-nonsense",
parserVersion: "3.1.0",
want: fmt.Errorf("error comparing document schema version with parser schema version: %w", errors.New("Invalid Semantic Version")),
want: fmt.Errorf("error comparing document schema version with parser schema version: %w", errors.New("invalid semantic version")),
}, {
name: "warning when parser version is unparseable",
documentVersion: "7.1.0",
parserVersion: "some-nonsense",
want: fmt.Errorf("error comparing document schema version with parser schema version: %w", errors.New("Invalid Semantic Version")),
want: fmt.Errorf("error comparing document schema version with parser schema version: %w", errors.New("invalid semantic version")),
}}
for _, tt := range tests {
+24
View File
@@ -1,5 +1,10 @@
package model
import (
"encoding/json"
"fmt"
)
// Document represents the syft cataloging findings as a JSON document
type Document struct {
Artifacts []Package `json:"artifacts"` // Artifacts is the list of packages discovered and placed into the catalog
@@ -11,6 +16,25 @@ type Document struct {
Schema Schema `json:"schema"` // Schema is a block reserved for defining the version for the shape of this JSON document and where to find the schema document to validate the shape
}
func (d *Document) UnmarshalJSON(data []byte) error {
type Alias *Document
aux := Alias(d)
if err := json.Unmarshal(data, aux); err != nil {
return fmt.Errorf("could not unmarshal syft JSON document: %w", err)
}
// in previous versions of anchorectl, the file modes were stored as decimal values instead of octal.
if d.Schema.Version == "1.0.0" && d.Descriptor.Name == "anchorectl" {
// convert all file modes from decimal to octal
for i := range d.Files {
d.Files[i].Metadata.Mode = convertBase10ToBase8(d.Files[i].Metadata.Mode)
}
}
return nil
}
// Descriptor describes what created the document as well as surrounding metadata
type Descriptor struct {
Name string `json:"name"`
@@ -0,0 +1,99 @@
package model
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDocumentUnmarshalJSON_SchemaDetection(t *testing.T) {
tests := []struct {
name string
jsonData string
modes []int
}{
{
name: "schema version 1.0.0 + anchorectl",
jsonData: `{
"files": [
{"metadata": {"mode": 493}},
{"metadata": {"mode": 420}}
],
"schema": {"version": "1.0.0"},
"descriptor": {
"name": "anchorectl"
}
}`,
modes: []int{755, 644},
},
{
name: "schema version 1.0.0 + syft",
jsonData: `{
"files": [
{"metadata": {"mode": 755}},
{"metadata": {"mode": 644}}
],
"schema": {"version": "1.0.0"},
"descriptor": {
"name": "syft"
}
}`,
modes: []int{755, 644},
},
{
name: "schema version 2.0.0 + anchorectl",
jsonData: `{
"files": [
{"metadata": {"mode": 755}},
{"metadata": {"mode": 644}}
],
"schema": {"version": "2.0.0"},
"descriptor": {
"name": "anchorectl"
}
}`,
modes: []int{755, 644},
},
{
name: "missing schema version should not convert modes",
jsonData: `{
"files": [
{"metadata": {"mode": 755}}
],
"schema": {}
}`,
modes: []int{755},
},
{
name: "empty files array with version 1.0.0",
jsonData: `{
"files": [],
"schema": {"version": "1.0.0"},
"descriptor": {
"name": "anchorectl"
}
}`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var doc Document
err := json.Unmarshal([]byte(tt.jsonData), &doc)
if err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
var modes []int
for _, file := range doc.Files {
modes = append(modes, file.Metadata.Mode)
}
require.Len(t, doc.Files, len(tt.modes), "Unexpected number of files")
assert.Equal(t, tt.modes, modes, "File modes do not match expected values")
})
}
}
+92
View File
@@ -1,6 +1,11 @@
package model
import (
"encoding/json"
"fmt"
"strconv"
stereoFile "github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/license"
)
@@ -26,6 +31,57 @@ type FileMetadataEntry struct {
Size int64 `json:"size"`
}
type auxFileMetadataEntry FileMetadataEntry
type fileMetadataEntryWithLegacyHint struct {
*auxFileMetadataEntry `json:",inline"`
LegacyHint any `json:"FileInfo"`
}
func (f *FileMetadataEntry) UnmarshalJSON(data []byte) error {
aux := fileMetadataEntryWithLegacyHint{
auxFileMetadataEntry: (*auxFileMetadataEntry)(f),
}
if err := json.Unmarshal(data, &aux); err == nil {
fieldsSpecified := f.Mode != 0 || f.Type != "" || f.LinkDestination != "" ||
f.UserID != 0 || f.GroupID != 0 || f.MIMEType != "" || f.Size != 0
if aux.LegacyHint == nil && fieldsSpecified {
// we should have at least one field set to a non-zero value... (this is not a legacy shape)
return nil
}
}
var legacy sbomImportLegacyFileMetadataEntry
if err := json.Unmarshal(data, &legacy); err != nil {
return err
}
if !legacy.Type.WasInt {
// this occurs for document shapes from a non-import path and indicates that the mode has already been converted to octal.
// That being said, we want to handle all legacy shapes the same, so we will convert this to base 10 for consistency.
legacy.Mode = convertBase8ToBase10(legacy.Mode)
}
f.Mode = legacy.Mode
f.Type = legacy.Type.Value
f.LinkDestination = legacy.LinkDestination
f.UserID = legacy.UserID
f.GroupID = legacy.GroupID
f.MIMEType = legacy.MIMEType
f.Size = legacy.Size
return nil
}
type sbomImportLegacyFileMetadataEntry struct {
Mode int `json:"Mode"`
Type intOrStringFileType `json:"Type"`
LinkDestination string `json:"LinkDestination"`
UserID int `json:"UserID"`
GroupID int `json:"GroupID"`
MIMEType string `json:"MIMEType"`
Size int64 `json:"Size"`
}
type FileLicense struct {
Value string `json:"value"`
SPDXExpression string `json:"spdxExpression"`
@@ -38,3 +94,39 @@ type FileLicenseEvidence struct {
Offset int `json:"offset"`
Extent int `json:"extent"`
}
type intOrStringFileType struct {
Value string
WasInt bool
}
func (lt *intOrStringFileType) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err == nil {
lt.Value = str
return nil
}
var num stereoFile.Type
if err := json.Unmarshal(data, &num); err != nil {
return fmt.Errorf("file.Type must be either string or int, got: %s", string(data))
}
lt.Value = num.String()
lt.WasInt = true
return nil
}
func convertBase10ToBase8(rawMode int) int {
octalStr := fmt.Sprintf("%o", rawMode)
// we don't need to check that this is a valid octal string since the input is always an integer
result, _ := strconv.Atoi(octalStr)
return result
}
func convertBase8ToBase10(octalMode int) int {
octalStr := strconv.Itoa(octalMode)
result, _ := strconv.ParseInt(octalStr, 8, 64)
return int(result)
}
+320
View File
@@ -0,0 +1,320 @@
package model
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_FileMetadataEntry_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
jsonData []byte
expected FileMetadataEntry
}{
{
name: "unmarshal current format",
jsonData: []byte(`{
"mode": 644,
"type": "RegularFile",
"linkDestination": "/usr/bin/python3",
"userID": 1000,
"groupID": 1000,
"mimeType": "text/plain",
"size": 10174
}`),
expected: FileMetadataEntry{
Mode: 644,
Type: "RegularFile",
LinkDestination: "/usr/bin/python3",
UserID: 1000,
GroupID: 1000,
MIMEType: "text/plain",
Size: 10174,
},
},
{
name: "unmarshal legacy image add internal document format",
jsonData: []byte(`{
"FileInfo": {},
"Mode": 644,
"Type": "RegularFile",
"LinkDestination": "/usr/bin/python3",
"UserID": 1000,
"GroupID": 1000,
"MIMEType": "text/plain",
"Size": 10174
}`),
expected: FileMetadataEntry{
Mode: 420, // important! we convert this to base 10 so that all documents are consistent
Type: "RegularFile",
LinkDestination: "/usr/bin/python3",
UserID: 1000,
GroupID: 1000,
MIMEType: "text/plain",
Size: 10174,
},
},
{
name: "unmarshal legacy sbom import format",
jsonData: []byte(`{
"FileInfo": {},
"Mode": 644,
"Type": 0,
"LinkDestination": "/usr/bin/python3",
"UserID": 1000,
"GroupID": 1000,
"MIMEType": "text/plain",
"Size": 10174
}`),
expected: FileMetadataEntry{
Mode: 644,
Type: "RegularFile",
LinkDestination: "/usr/bin/python3",
UserID: 1000,
GroupID: 1000,
MIMEType: "text/plain",
Size: 10174,
},
},
{
name: "unmarshal minimal current format",
jsonData: []byte(`{
"mode": 0,
"type": "RegularFile",
"userID": 0,
"groupID": 0,
"size": 0
}`),
expected: FileMetadataEntry{
Type: "RegularFile",
},
},
{
name: "unmarshal minimal legacy format",
jsonData: []byte(`{
"FileInfo": {},
"Mode": 0,
"Type": "RegularFile",
"UserID": 0,
"GroupID": 0,
"Size": 0
}`),
expected: FileMetadataEntry{
Type: "RegularFile",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var actual FileMetadataEntry
err := actual.UnmarshalJSON(test.jsonData)
require.NoError(t, err)
if diff := cmp.Diff(test.expected, actual); diff != "" {
t.Errorf("FileMetadataEntry mismatch (-expected +actual):\n%s", diff)
}
})
}
}
func Test_intOrStringFileType_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
jsonData []byte
expected string
expectedWasInt bool
wantErr require.ErrorAssertionFunc
}{
// string inputs - should pass through unchanged
{
name: "string RegularFile",
jsonData: []byte(`"RegularFile"`),
expected: "RegularFile",
},
{
name: "string HardLink",
jsonData: []byte(`"HardLink"`),
expected: "HardLink",
},
{
name: "string Directory",
jsonData: []byte(`"Directory"`),
expected: "Directory",
},
{
name: "string custom value",
jsonData: []byte(`"CustomFileType"`),
expected: "CustomFileType",
},
// integer inputs - should convert to string representation
{
name: "int 0 (TypeRegular)",
jsonData: []byte(`0`),
expected: "RegularFile",
expectedWasInt: true,
},
{
name: "int 1 (TypeHardLink)",
jsonData: []byte(`1`),
expected: "HardLink",
expectedWasInt: true,
},
{
name: "int 2 (TypeSymLink)",
jsonData: []byte(`2`),
expected: "SymbolicLink",
expectedWasInt: true,
},
{
name: "int 3 (TypeCharacterDevice)",
jsonData: []byte(`3`),
expected: "CharacterDevice",
expectedWasInt: true,
},
{
name: "int 4 (TypeBlockDevice)",
jsonData: []byte(`4`),
expected: "BlockDevice",
expectedWasInt: true,
},
{
name: "int 5 (TypeDirectory)",
jsonData: []byte(`5`),
expected: "Directory",
expectedWasInt: true,
},
{
name: "int 6 (TypeFIFO)",
jsonData: []byte(`6`),
expected: "FIFONode",
expectedWasInt: true,
},
{
name: "int 7 (TypeSocket)",
jsonData: []byte(`7`),
expected: "Socket",
expectedWasInt: true,
},
{
name: "int 8 (TypeIrregular)",
jsonData: []byte(`8`),
expected: "IrregularFile",
expectedWasInt: true,
},
{
name: "unknown int",
jsonData: []byte(`99`),
expected: "Unknown",
expectedWasInt: true,
},
{
name: "negative int",
jsonData: []byte(`-1`),
expected: "Unknown",
expectedWasInt: true,
},
{
name: "null value",
jsonData: []byte(`null`),
},
{
name: "invalid JSON",
jsonData: []byte(`{`),
wantErr: require.Error,
},
{
name: "boolean value",
jsonData: []byte(`true`),
wantErr: require.Error,
},
{
name: "array value",
jsonData: []byte(`[]`),
wantErr: require.Error,
},
{
name: "object value",
jsonData: []byte(`{}`),
wantErr: require.Error,
},
{
name: "float value",
jsonData: []byte(`1.5`),
wantErr: require.Error,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.wantErr == nil {
test.wantErr = require.NoError
}
var ft intOrStringFileType
err := ft.UnmarshalJSON(test.jsonData)
test.wantErr(t, err)
if err != nil {
return
}
assert.Equal(t, test.expected, ft.Value)
assert.Equal(t, test.expectedWasInt, ft.WasInt)
})
}
}
func Test_convertBase10ToBase8(t *testing.T) {
tests := []struct {
name string
input int
expected int
}{
{
name: "no permissions",
input: 0,
expected: 0,
},
{
name: "symlink + rwxrwxrwx",
input: 134218239,
expected: 1000000777,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual := convertBase10ToBase8(tt.input)
require.Equal(t, tt.expected, actual)
})
}
}
func Test_convertBase8ToBase10(t *testing.T) {
tests := []struct {
name string
input int
expected int
}{
{
name: "no permissions",
input: 0,
expected: 0,
},
{
name: "symlink + rwxrwxrwx",
input: 1000000777,
expected: 134218239,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual := convertBase8ToBase10(tt.input)
require.Equal(t, tt.expected, actual)
})
}
}
@@ -25,6 +25,7 @@ type LinuxRelease struct {
PrivacyPolicyURL string `json:"privacyPolicyURL,omitempty"`
CPEName string `json:"cpeName,omitempty"`
SupportEnd string `json:"supportEnd,omitempty"`
ExtendedSupport bool `json:"extendedSupport,omitempty"`
}
func (s *IDLikes) UnmarshalJSON(data []byte) error {
+1
View File
@@ -204,5 +204,6 @@ func unpackPkgMetadata(p *Package, unpacker packageMetadataUnpacker) error {
}
}
p.Metadata = reflect.ValueOf(val).Elem().Interface()
p.MetadataType = ty
return nil
}
+45
View File
@@ -145,6 +145,51 @@ func TestSource_UnmarshalJSON(t *testing.T) {
},
},
},
{
name: "snap",
input: []byte(`{
"id": "foobar",
"name": "etcd",
"version": "3.4.36",
"type": "snap",
"metadata": {
"summary": "Distributed reliable key-value store",
"base": "core18",
"grade": "stable",
"confinement": "strict",
"architectures": [
"amd64"
],
"digests": [
{
"algorithm": "sha256",
"value": "6700d789d2c38b0f7513058ddcea8f9a275e2206b4621a772eb065e12069956e"
}
]
}
}`),
expected: &Source{
ID: "foobar",
Name: "etcd",
Version: "3.4.36",
Type: "snap",
Metadata: source.SnapMetadata{
Summary: "Distributed reliable key-value store",
Base: "core18",
Grade: "stable",
Confinement: "strict",
Architectures: []string{
"amd64",
},
Digests: []file.Digest{
{
Algorithm: "sha256",
Value: "6700d789d2c38b0f7513058ddcea8f9a275e2206b4621a772eb065e12069956e",
},
},
},
},
},
{
name: "unknown source type",
input: []byte(`{
+3 -2
View File
@@ -41,7 +41,7 @@ func ToFormatModel(s sbom.SBOM, cfg EncoderConfig) model.Document {
ArtifactRelationships: toRelationshipModel(s.Relationships),
Files: toFile(s, coordinateSorter),
Source: toSourceModel(s.Source),
Distro: toLinuxReleaser(s.Artifacts.LinuxDistribution),
Distro: toLinuxRelease(s.Artifacts.LinuxDistribution),
Descriptor: toDescriptor(s.Descriptor),
Schema: model.Schema{
Version: internal.JSONSchemaVersion,
@@ -50,7 +50,7 @@ func ToFormatModel(s sbom.SBOM, cfg EncoderConfig) model.Document {
}
}
func toLinuxReleaser(d *linux.Release) model.LinuxRelease {
func toLinuxRelease(d *linux.Release) model.LinuxRelease {
if d == nil {
return model.LinuxRelease{}
}
@@ -73,6 +73,7 @@ func toLinuxReleaser(d *linux.Release) model.LinuxRelease {
PrivacyPolicyURL: d.PrivacyPolicyURL,
CPEName: d.CPEName,
SupportEnd: d.SupportEnd,
ExtendedSupport: d.ExtendedSupport,
}
}
@@ -127,6 +127,36 @@ func Test_toSourceModel(t *testing.T) {
},
},
},
{
name: "snap",
src: source.Description{
ID: "test-id",
Name: "some-name",
Version: "some-version",
Metadata: source.SnapMetadata{
Summary: "some summary",
Base: "some/base",
Grade: "some grade",
Confinement: "some confinement",
Architectures: []string{"x86_64", "arm64"},
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
},
},
expected: model.Source{
ID: "test-id",
Name: "some-name",
Version: "some-version",
Type: "snap",
Metadata: source.SnapMetadata{
Summary: "some summary",
Base: "some/base",
Grade: "some grade",
Confinement: "some confinement",
Architectures: []string{"x86_64", "arm64"},
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
},
},
},
// below are regression tests for when the name/version are not provided
// historically we've hoisted up the name/version from the metadata, now it is a simple pass-through
{
+6 -6
View File
@@ -40,7 +40,7 @@ func toSyftModel(doc model.Document) *sbom.SBOM {
FileLicenses: fileArtifacts.FileLicenses,
Executables: fileArtifacts.Executables,
Unknowns: fileArtifacts.Unknowns,
LinuxDistribution: toSyftLinuxRelease(doc.Distro),
LinuxDistribution: toInternalLinuxRelease(doc.Distro),
},
Source: *toSyftSourceData(doc.Source),
Descriptor: toSyftDescriptor(doc.Descriptor),
@@ -144,13 +144,12 @@ func toSyftFiles(files []model.File) sbom.Artifacts {
}
func safeFileModeConvert(val int) (fs.FileMode, error) {
if val < math.MinInt32 || val > math.MaxInt32 {
// Value is out of the range that int32 can represent
mode, err := strconv.ParseInt(strconv.Itoa(val), 8, 64)
if mode < 0 || mode > math.MaxUint32 {
// value is out of the range that int32 can represent
return 0, fmt.Errorf("value %d is out of the range that int32 can represent", val)
}
// Safe to convert to os.FileMode
mode, err := strconv.ParseInt(strconv.Itoa(val), 8, 64)
if err != nil {
return 0, err
}
@@ -196,7 +195,7 @@ func toSyftFileType(ty string) stereoscopeFile.Type {
}
}
func toSyftLinuxRelease(d model.LinuxRelease) *linux.Release {
func toInternalLinuxRelease(d model.LinuxRelease) *linux.Release {
if cmp.Equal(d, model.LinuxRelease{}) {
return nil
}
@@ -219,6 +218,7 @@ func toSyftLinuxRelease(d model.LinuxRelease) *linux.Release {
PrivacyPolicyURL: d.PrivacyPolicyURL,
CPEName: d.CPEName,
SupportEnd: d.SupportEnd,
ExtendedSupport: d.ExtendedSupport,
}
}
@@ -100,6 +100,36 @@ func Test_toSyftSourceData(t *testing.T) {
},
},
},
{
name: "snap",
src: model.Source{
ID: "the-id",
Name: "some-name",
Version: "some-version",
Type: "snap",
Metadata: source.SnapMetadata{
Summary: "something!",
Base: "base!",
Grade: "grade!",
Confinement: "confined!",
Architectures: []string{"arch!"},
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest!"}},
},
},
expected: &source.Description{
ID: "the-id",
Name: "some-name",
Version: "some-version",
Metadata: source.SnapMetadata{
Summary: "something!",
Base: "base!",
Grade: "grade!",
Confinement: "confined!",
Architectures: []string{"arch!"},
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest!"}},
},
},
},
// below are regression tests for when the name/version are not provided
// historically we've hoisted up the name/version from the metadata, now it is a simple pass-through
{
@@ -491,6 +521,12 @@ func Test_safeFileModeConvert(t *testing.T) {
want: os.FileMode(511), // 777 in octal equals 511 in decimal
wantErr: false,
},
{
name: "valid perm with symlink type",
val: 1000000777, // symlink + rwxrwxrwx
want: os.FileMode(0o1000000777), // 134218239
wantErr: false,
},
{
name: "outside int32 high",
val: int(math.MaxInt32) + 1,
+83 -16
View File
@@ -8,6 +8,8 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
"github.com/anchore/syft/syft/sbom"
)
@@ -66,25 +68,90 @@ func (e encoder) Encode(writer io.Writer, s sbom.SBOM) error {
columns = append(columns, "") // add a column for duplicate annotations
rows = markDuplicateRows(rows)
table := tablewriter.NewWriter(writer)
table := newTableWriter(writer, columns)
table.SetHeader(columns)
table.SetHeaderLine(false)
table.SetBorder(false)
table.SetAutoWrapText(false)
table.SetAutoFormatHeaders(true)
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetRowSeparator("")
table.SetTablePadding(" ")
table.SetNoWhiteSpace(true)
if err := table.Bulk(rows); err != nil {
return fmt.Errorf("failed to add table rows: %w", err)
}
table.AppendBulk(rows)
table.Render()
return table.Render()
}
return nil
func newTableWriter(writer io.Writer, columns []string) *tablewriter.Table {
// Here’s a simplified diagram of a table with a header, rows, and footer:
//
// [Borders.Top]
// | Header1 | Header2 | (Line below header: Lines.ShowTop)
// [Separators.BetweenRows]
// | Row1 | Row1 |
// [Separators.BetweenRows]
// | Row2 | Row2 |
// [Lines.ShowBottom]
// | Footer1 | Footer2 |
// [Borders.Bottom]
//
// So for example:
// ┌──────┬─────┐ <- Borders.Top
// │ NAME │ AGE │
// ├──────┼─────┤ <- Lines.ShowTop
// │ Alice│ 25 │
// ├──────┼─────┤ <- Separators.BetweenRows
// │ Bob │ 30 │
// ├──────┼─────┤ <- Lines.ShowBottom
// │ Total│ 2 │
// └──────┴─────┘ <- Borders.Bottom
return tablewriter.NewTable(writer,
tablewriter.WithHeader(columns),
tablewriter.WithHeaderAutoFormat(tw.On),
tablewriter.WithHeaderAutoWrap(tw.WrapNone),
tablewriter.WithHeaderAlignment(tw.AlignLeft),
tablewriter.WithRowAutoFormat(tw.Off),
tablewriter.WithRowAutoWrap(tw.WrapNone),
tablewriter.WithRowAlignment(tw.AlignLeft),
tablewriter.WithTrimSpace(tw.On),
tablewriter.WithAutoHide(tw.On),
tablewriter.WithRenderer(renderer.NewBlueprint()),
tablewriter.WithBehavior(
tw.Behavior{
TrimSpace: tw.On,
AutoHide: tw.On,
},
),
tablewriter.WithPadding(
tw.Padding{
Left: "",
Right: " ",
Top: "",
Bottom: "",
},
),
tablewriter.WithRendition(
tw.Rendition{
Symbols: tw.NewSymbols(tw.StyleNone),
Borders: tw.Border{
Left: tw.Off,
Top: tw.Off,
Right: tw.Off,
Bottom: tw.Off,
},
Settings: tw.Settings{
Separators: tw.Separators{
ShowHeader: tw.Off,
ShowFooter: tw.Off,
BetweenRows: tw.Off,
BetweenColumns: tw.Off,
},
Lines: tw.Lines{
ShowTop: tw.Off,
ShowBottom: tw.Off,
ShowHeaderLine: tw.Off,
ShowFooterLine: tw.Off,
},
},
},
),
)
}
func markDuplicateRows(items [][]string) [][]string {

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