Compare commits

...
45 Commits
Author SHA1 Message Date
Harm Weites 356f7c92b4 fix: match OpenSSL letter releases (#2682)
* chore: match openssl 1.1 letter releases

Signed-off-by: Harm Weites <harm@weites.com>

* chore: include image sha

Signed-off-by: Harm Weites <harm@weites.com>

---------

Signed-off-by: Harm Weites <harm@weites.com>
2024-02-29 14:39:23 +00:00
Alex Goodman 6377465440 Mark duplicated rows in table output (#2679)
* mark duplicated rows in table output

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

* fix unit test

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

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-29 09:33:00 -05:00
William Murphy 3ad91f2678 fix: trim path from deps.json in portable way (#2674)
* fix: trim path from deps.json in portable way

Previously, the path trimming regex would leave leading path separator
in place on Windows.

Probably a better long term fix is to a library path operation.

Signed-off-by: Will Murphy <will.murphy@anchore.com>
2024-02-29 09:31:55 -05:00
anchore-actions-token-generator[bot]andspiffcs 5ef83fdc79 chore(deps): update tools to latest versions (#2680)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-02-29 09:27:37 -05:00
Alex Goodman 06ff1a353a enforce breaking change bump major version (#2635)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-28 15:48:20 -05:00
Keith Zantow 326ec57d4a docs: fix incorrect flag name in readme (#2677) 2024-02-28 15:39:43 -05:00
Alex Goodman 48e5672a87 Consider filesystem types for mount points when ignoring system paths (#2675)
* consider fs types for mount points when ignoring system paths

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

* address feedback

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

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-28 15:37:17 -05:00
William Murphy 63171b55dd fix: stop emitting bus events on go mod events (#2673)
Previously, the TUI would hang when scanning directories with lots of go
packages, possibly because this path was spamming the TUI with too
many events. Since checking on a particular go module is fast, don't
show TUI events for each one.

Signed-off-by: Will Murphy <will.murphy@anchore.com>
2024-02-28 14:14:46 -05:00
dependabot[bot] acc473fc30 chore(deps): bump peter-evans/create-pull-request from 6.0.0 to 6.0.1 (#2676)
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/b1ddad2c994a25fbc81a28b3ec0e368bb2021c50...a4f52f8033a6168103c2538976c07b467e8163bc)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-28 09:31:29 -05:00
Keith Zantow a978966cad feat: add --from flag, refactor source providers (#2610)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-02-27 16:44:37 -05:00
dependabot[bot] 928511ea0f chore(deps): bump modernc.org/sqlite from 1.29.1 to 1.29.2 (#2671) 2024-02-26 10:57:06 -05:00
dependabot[bot] 33b72ccbf8 chore(deps): bump github/codeql-action from 3.24.4 to 3.24.5 (#2666) 2024-02-23 14:10:26 +00:00
Keith Zantow 2995c3c4fd fix: SPDX tag value version selector (#2665)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-02-23 08:22:10 -05:00
Stefan Hacker 170ac079d4 fix(install): return appropriate error codes (#2664)
Signed-off-by: Stefan Hacker <mail@hacst.net>
2024-02-22 19:34:51 -05:00
Keith Zantow 108a5dae9b chore: update busybox image for acceptance tests (#2663)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-02-22 15:32:17 -05:00
dependabot[bot] cdf1e0bacb chore(deps): bump github/codeql-action from 3.24.3 to 3.24.4 (#2662) 2024-02-22 16:50:53 +00:00
Alex Goodman 0c3b8ca4ed rename binary classifier cataloger name (#2643)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-20 13:52:11 -05:00
Alex Goodman 434b6ad506 add cataloger selection example (#2646)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-20 11:44:42 -05:00
anchore-actions-token-generator[bot]andspiffcs 3598cb4f8f chore(deps): update tools to latest versions (#2651)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-02-20 11:39:54 -05:00
anchore-actions-token-generator[bot] 8260bce057 chore(deps): update stereoscope to 6171ee21e1d584f6bde910f354d126c9cd70deaa (#2655) 2024-02-17 10:22:56 -05:00
dependabot[bot] 578ac9cf2d chore(deps): bump github/codeql-action from 3.24.1 to 3.24.3 (#2649)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.24.1 to 3.24.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/e675ced7a7522a761fc9c8eb26682c8b27c42b2b...379614612a29c9e28f31f39a59013eb8012a51f0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-15 09:13:29 -05:00
Alex Goodman a1b23bd57d add syft version used to SBOM tool info by default (#2647)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-14 16:57:31 -05:00
Alex Goodman 65cadda486 Survive indexing dead symlinks (#2645)
* survive indexing branches that start with a bad symlink

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

* add log statement

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

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-14 21:06:22 +00:00
Alex Goodman a909e3cec9 fix considering base path when ignoring known bad unix paths (#2644)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-14 15:57:38 -05:00
Alex Goodman 8e62ff9831 test for field conventions in json schema (#2642)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-14 11:11:53 -05:00
Alexandr HacicheantandAlex Goodman 96ee2db875 feat: Add Wordpress cataloger (#2218)
* Closes #1911 Wordpress cataloger

Signed-off-by: disc <a.hacicheant@gmail.com>

* Fixed a few unit tests and static analizer notices

Signed-off-by: disc <a.hacicheant@gmail.com>

* Updated `README.md`

Signed-off-by: disc <a.hacicheant@gmail.com>

* Fixed `golangci-lint` notices
Added integration test for `wordpress-plugin`

Signed-off-by: disc <a.hacicheant@gmail.com>

* Fixed `gosimports` notices

Signed-off-by: disc <a.hacicheant@gmail.com>

* Updated `json schema` version

Signed-off-by: disc <a.hacicheant@gmail.com>

* Fixed CLI tests, increased expected package count

Signed-off-by: disc <a.hacicheant@gmail.com>

* Read first 4Kb of a plugins file's content

Signed-off-by: disc <a.hacicheant@gmail.com>

* replace JSON schema version

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

* change wording on source info for wordpress packages

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

* Minor changes after a huge refactoring

Signed-off-by: disc <a.hacicheant@gmail.com>

* Removed unused files

Signed-off-by: disc <a.hacicheant@gmail.com>

* Updated schema

Signed-off-by: disc <a.hacicheant@gmail.com>

* Fixed integration tests

Signed-off-by: disc <a.hacicheant@gmail.com>

* fix integration tests

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

* Renamed `metadata.Name` to `metadata.PluginInstallDirectory`

Signed-off-by: disc <a.hacicheant@gmail.com>

* rename fields to be compliant with json conventions

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

---------

Signed-off-by: disc <a.hacicheant@gmail.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-14 16:03:25 +00:00
Alex Goodman 98b700e83c rename binary cataloger to be more unique (#2633)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-14 11:01:55 -05:00
Christopher Angelo Phillips 9803db2949 fix: update runner size to use larger HD for codeql (#2641)
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2024-02-14 10:31:05 -05:00
17ef243956 chore(deps): update tools to latest versions (#2616)
* chore(deps): update tools to latest versions

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

* fix: update to new linter rules

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

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
2024-02-14 14:59:49 +00:00
dependabot[bot] 3ac7369068 chore(deps): bump github/codeql-action from 3.24.0 to 3.24.1 (#2638)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.24.0 to 3.24.1.
- [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/e8893c57a1f3a2b659b6b55564fdfdbbd2982911...e675ced7a7522a761fc9c8eb26682c8b27c42b2b)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-14 09:21:21 -05:00
dependabot[bot] 4d4efa4963 chore(deps): bump dawidd6/action-homebrew-bump-formula (#2639)
Bumps [dawidd6/action-homebrew-bump-formula](https://github.com/dawidd6/action-homebrew-bump-formula) from 3.10.1 to 3.11.0.
- [Release notes](https://github.com/dawidd6/action-homebrew-bump-formula/releases)
- [Commits](https://github.com/dawidd6/action-homebrew-bump-formula/compare/75ed025ff3ad1d617862838b342b06d613a0ddf3...baf2b60c51fc1f8453c884b0c61052668a71bd1d)

---
updated-dependencies:
- dependency-name: dawidd6/action-homebrew-bump-formula
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-14 09:21:05 -05:00
dependabot[bot] a7da2270c7 chore(deps): bump modernc.org/sqlite from 1.29.0 to 1.29.1 (#2640)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.29.0 to 1.29.1.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.29.0...v1.29.1)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-14 09:20:54 -05:00
Keith Zantow 6288530835 fix: add BOMRef to CycloneDX OS Component (#2634) 2024-02-14 08:18:16 -05:00
dependabot[bot] 25d3c06962 chore(deps): bump github.com/saferwall/pe from 1.5.0 to 1.5.2 (#2629)
Bumps [github.com/saferwall/pe](https://github.com/saferwall/pe) from 1.5.0 to 1.5.2.
- [Release notes](https://github.com/saferwall/pe/releases)
- [Changelog](https://github.com/saferwall/pe/blob/main/CHANGELOG.md)
- [Commits](https://github.com/saferwall/pe/compare/v1.5.0...v1.5.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-13 11:23:35 -05:00
dependabot[bot] 79b71be0ee chore(deps): bump modernc.org/sqlite from 1.28.0 to 1.29.0 (#2630)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.28.0 to 1.29.0.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.28.0...v1.29.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>
2024-02-13 11:23:22 -05:00
Alex Goodman 25ae7bf55f fix getting union reader for sif images (#2631)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-13 15:12:31 +00:00
dependabot[bot] e72dec8e9e chore(deps): bump golang.org/x/net from 0.20.0 to 0.21.0 (#2607)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.20.0 to 0.21.0.
- [Commits](https://github.com/golang/net/compare/v0.20.0...v0.21.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 14:31:44 -05:00
dependabot[bot] 3398e72066 chore(deps): bump github.com/saferwall/pe from 1.4.8 to 1.5.0 (#2625)
Bumps [github.com/saferwall/pe](https://github.com/saferwall/pe) from 1.4.8 to 1.5.0.
- [Release notes](https://github.com/saferwall/pe/releases)
- [Changelog](https://github.com/saferwall/pe/blob/main/CHANGELOG.md)
- [Commits](https://github.com/saferwall/pe/compare/v1.4.8...v1.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 14:31:31 -05:00
Keith Zantow d26a5c4d30 fix: ensure version output to stdout (#2621) 2024-02-09 20:59:25 +00:00
Alex Goodman 84576b93e1 Guess go main module version based on binary contents (#2608)
* guess go main module version based on binary contents

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

* add configuration options for golang main module version heuristics

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

* fix test setup for go bin cataloger

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

* fix unit test

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

* fix incorrect test assert ordering

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

* handle error from seek

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

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-09 19:52:42 +00:00
737c4e44c5 chore(deps): update stereoscope to 681f6715b0e35686d6e6f40bce109176de1ee274 (#2617)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kzantow <3009477+kzantow@users.noreply.github.com>
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
2024-02-09 14:06:28 -05:00
Alex Goodman 7444a9f976 fix readme around templating options (#2612)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-09 13:44:41 -05:00
Alex Goodman 8683cba081 suppress executable parsing issues (#2614)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2024-02-09 17:13:58 +00:00
Christopher Angelo Phillips c0f43e5e2d chore: update license list, cpe dictionary (#2620)
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2024-02-09 11:31:42 -05:00
anchore-actions-token-generator[bot]andspiffcs 397cf210de chore(deps): update tools to latest versions (#2606)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: spiffcs <32073428+spiffcs@users.noreply.github.com>
2024-02-08 10:39:18 -05:00
159 changed files with 7204 additions and 1467 deletions
+3 -3
View File
@@ -26,7 +26,7 @@ tools:
# used for linting
- name: golangci-lint
version:
want: v1.55.2
want: v1.56.2
method: github-release
with:
repo: golangci/golangci-lint
@@ -103,7 +103,7 @@ tools:
# used for running all local and CI tasks
- name: task
version:
want: v3.34.1
want: v3.35.0
method: github-release
with:
repo: go-task/task
@@ -111,7 +111,7 @@ tools:
# used for triggering a release
- name: gh
version:
want: v2.43.1
want: v2.44.1
method: github-release
with:
repo: cli/cli
+1 -1
View File
@@ -1,4 +1,4 @@
enforce-v0: true # don't make breaking-change label bump major version before 1.0.
enforce-v0: false
title: ""
github:
+4 -4
View File
@@ -20,7 +20,7 @@ permissions:
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
runs-on: ubuntu-22.04-4core-16gb
permissions:
security-events: write
@@ -45,7 +45,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 #v3.24.0
uses: github/codeql-action/init@47b3d888fe66b639e431abf22ebca059152f1eea #v3.24.5
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -56,7 +56,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 #v3.24.0
uses: github/codeql-action/autobuild@47b3d888fe66b639e431abf22ebca059152f1eea #v3.24.5
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -70,4 +70,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 #v3.24.0
uses: github/codeql-action/analyze@47b3d888fe66b639e431abf22ebca059152f1eea #v3.24.5
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
echo -n "commit=$(git rev-parse HEAD)" | tee -a $GITHUB_OUTPUT
- name: Update Homebrew formula
uses: dawidd6/action-homebrew-bump-formula@75ed025ff3ad1d617862838b342b06d613a0ddf3 # v3.10.1
uses: dawidd6/action-homebrew-bump-formula@baf2b60c51fc1f8453c884b0c61052668a71bd1d # v3.11.0
with:
token: ${{ secrets.HOMEBREW_TOKEN }}
org: anchore
+1 -1
View File
@@ -50,7 +50,7 @@ jobs:
app_id: ${{ secrets.TOKEN_APP_ID }}
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
- uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50 #v6.0.0
- uses: peter-evans/create-pull-request@a4f52f8033a6168103c2538976c07b467e8163bc #v6.0.1
with:
signoff: true
delete-branch: true
@@ -33,7 +33,7 @@ jobs:
app_id: ${{ secrets.TOKEN_APP_ID }}
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
- uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50 #v6.0.0
- uses: peter-evans/create-pull-request@a4f52f8033a6168103c2538976c07b467e8163bc #v6.0.1
with:
signoff: true
delete-branch: true
@@ -44,7 +44,7 @@ jobs:
app_id: ${{ secrets.TOKEN_APP_ID }}
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
- uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50 #v6.0.0
- uses: peter-evans/create-pull-request@a4f52f8033a6168103c2538976c07b467e8163bc #v6.0.1
with:
signoff: true
delete-branch: true
+44 -23
View File
@@ -54,6 +54,7 @@ For commercial support options with Syft or Grype, please [contact Anchore](http
- Ruby (gem)
- Rust (cargo.lock)
- Swift (cocoapods, swift-package-manager)
- Wordpress plugins
## Installation
@@ -121,7 +122,8 @@ syft <image> --scope all-layers
### Supported sources
Syft can generate an SBOM from a variety of sources:
Syft can generate an SBOM from a variety of sources including images, files, directories, and archives. Syft will attempt to
determine the type of source based on provided input, for example:
```bash
# catalog a container image archive (from the result of `docker image save ...`, `podman save ...`, or `skopeo copy` commands)
@@ -134,26 +136,24 @@ syft path/to/image.sif
syft path/to/dir
```
Sources can be explicitly provided with a scheme:
To explicitly specify the source behavior, use the `--from` flag. Allowable options are:
```
docker:yourrepo/yourimage:tag use images from the Docker daemon
podman:yourrepo/yourimage:tag use images from the Podman daemon
containerd:yourrepo/yourimage:tag use images from the Containerd daemon
docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
singularity:path/to/yourimage.sif read directly from a Singularity Image Format (SIF) container on disk
dir:path/to/yourproject read directly from a path on disk (any directory)
file:path/to/yourproject/file read directly from a path on disk (any single file)
registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
docker use images from the Docker daemon
podman use images from the Podman daemon
containerd use images from the Containerd daemon
docker-archive use a tarball from disk for archives created from "docker save"
oci-archive use a tarball from disk for OCI archives (from Skopeo or otherwise)
oci-dir read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
singularity read directly from a Singularity Image Format (SIF) container on disk
dir read directly from a path on disk (any directory)
file read directly from a path on disk (any single file)
registry pull image directly from a registry (no container runtime required)
```
If a source is not provided and Syft identifies the input as a potential image reference, Syft will attempt to resolve it using:
the Docker, Podman, and Containerd daemons followed by direct registry access, in that order.
If an image source is not provided and cannot be detected from the given reference it is assumed the image should be pulled from the Docker daemon.
If docker is not present, then the Podman daemon is attempted next, followed by reaching out directly to the image registry last.
This default behavior can be overridden with the `default-image-pull-source` configuration option (See [Configuration](https://github.com/anchore/syft#configuration) for more details).
This default behavior can be overridden with the `default-image-pull-source` configuration option (See [Configuration](#configuration) for more details).
### File selection
@@ -228,12 +228,12 @@ syft <a directory> --select-catalogers "python"
Use the default set of catalogers and add a cataloger to the set:
```bash
syft ... --catalogers "+sbom-cataloger"
syft ... --select-catalogers "+sbom-cataloger"
```
Use the default set of catalogers but remove any catalogers that deal with RPMs:
```bash
syft ... --catalogers "-rpm"
syft ... --select-catalogers "-rpm"
```
Only scan with catalogers that:
@@ -305,7 +305,7 @@ Where the `formats` available are:
## Using templates
Syft lets you define custom output formats, using [Go templates](https://pkg.go.dev/text/template). Here's how it works:
Syft lets you define custom output formats, using [Go templates](https://pkg.go.dev/text/template) relative to the Syft JSON output. Here's how it works:
- Define your format as a Go template, and save this template as a file.
@@ -319,9 +319,9 @@ Syft lets you define custom output formats, using [Go templates](https://pkg.go.
Here's what the `csv.tmpl` file might look like:
```gotemplate
"Package","Version Installed","Found by"
{{- range .Artifacts}}
"{{.Name}}","{{.Version}}","{{.FoundBy}}"
"Package","Version Installed", "Found by"
{{- range .artifacts}}
"{{.name}}","{{.version}}","{{.foundBy}}"
{{- end}}
```
@@ -338,6 +338,9 @@ Syft also includes a vast array of utility templating functions from [sprig](htt
Lastly, Syft has custom templating functions defined in `./syft/format/template/encoder.go` to help parse the passed-in JSON structs.
> [!NOTE]
> If you have templates being used before Syft v0.102.0 that are no longer working. This is because templating keys were relative to the internal go structs before this version whereas now the keys are relative to the Syft JSON output. To get the legacy behavior back you can set the `format.template.legacy` option to `true` in your configuration.
## Multiple outputs
Syft can also output _multiple_ files in differing formats by appending
@@ -688,6 +691,24 @@ golang:
# SYFT_GOLANG_NOPROXY env var
no-proxy: ""
# the go main module version discovered from binaries built with the go compiler will
# always show (devel) as the version. Use these options to control heuristics to guess
# a more accurate version from the binary.
main-module-version:
# look for LD flags that appear to be setting a version (e.g. -X main.version=1.0.0)
# SYFT_GOLANG_MAIN_MODULE_VERSION_FROM_LD_FLAGS env var
from-ld-flags: true
# use the build settings (e.g. vcs.version & vcs.time) to craft a v0 pseudo version
# (e.g. v0.0.0-20220308212642-53e6d0aaf6fb) when a more accurate version cannot be found otherwise.
# SYFT_GOLANG_MAIN_MODULE_VERSION_FROM_BUILD_SETTINGS env var
from-build-settings: true
# search for semver-like strings in the binary contents.
# SYFT_GOLANG_MAIN_MODULE_VERSION_FROM_CONTENTS env var
from-contents: true
java:
maven-url: "https://repo1.maven.org/maven2"
max-parent-recursive-depth: 5
+1 -1
View File
@@ -48,7 +48,7 @@ func AppClioSetupConfig(id clio.Identification, out io.Writer) *clio.SetupConfig
return nil
},
).
WithPostRuns(func(state *clio.State, err error) {
WithPostRuns(func(_ *clio.State, _ error) {
stereoscope.Cleanup()
})
return clioCfg
+6 -9
View File
@@ -13,6 +13,7 @@ import (
"github.com/wagoodman/go-progress"
"github.com/anchore/clio"
"github.com/anchore/stereoscope"
"github.com/anchore/syft/cmd/syft/internal/options"
"github.com/anchore/syft/cmd/syft/internal/ui"
"github.com/anchore/syft/internal"
@@ -26,7 +27,6 @@ import (
"github.com/anchore/syft/syft/format/spdxtagvalue"
"github.com/anchore/syft/syft/format/syftjson"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
)
const (
@@ -247,7 +247,11 @@ func predicateType(outputName string) string {
}
func generateSBOMForAttestation(ctx context.Context, id clio.Identification, opts *options.Catalog, userInput string) (*sbom.SBOM, error) {
src, err := getSource(opts, userInput, onlyContainerImages)
if len(opts.From) > 1 || (len(opts.From) == 1 && opts.From[0] != stereoscope.RegistryTag) {
return nil, fmt.Errorf("attest requires use of an OCI registry directly, one or more of the specified sources is unsupported: %v", opts.From)
}
src, err := getSource(ctx, opts, userInput, stereoscope.RegistryTag)
if err != nil {
return nil, err
@@ -273,13 +277,6 @@ func generateSBOMForAttestation(ctx context.Context, id clio.Identification, opt
return s, nil
}
func onlyContainerImages(d *source.Detection) error {
if !d.IsContainerImage() {
return fmt.Errorf("attestations are only supported for oci images at this time")
}
return nil
}
func commandExists(cmd string) bool {
_, err := exec.LookPath(cmd)
return err == nil
+1 -1
View File
@@ -46,7 +46,7 @@ func CatalogerList(app clio.Application) *cobra.Command {
return app.SetupCommand(&cobra.Command{
Use: "list [OPTIONS]",
Short: "List available catalogers",
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
return runCatalogerList(opts)
},
}, opts)
+1 -1
View File
@@ -47,7 +47,7 @@ func Convert(app clio.Application) *cobra.Command {
}),
Args: validateConvertArgs,
PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
restoreStdout := ui.CaptureStdoutToTraceLog()
defer restoreStdout()
+43 -36
View File
@@ -13,6 +13,8 @@ import (
"gopkg.in/yaml.v3"
"github.com/anchore/clio"
"github.com/anchore/go-collections"
"github.com/anchore/stereoscope"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/cmd/syft/internal/options"
"github.com/anchore/syft/cmd/syft/internal/ui"
@@ -24,6 +26,7 @@ import (
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/sourceproviders"
)
const (
@@ -162,14 +165,23 @@ func validateArgs(cmd *cobra.Command, args []string, error string) error {
return cobra.MaximumNArgs(1)(cmd, args)
}
// nolint:funlen
func runScan(ctx context.Context, id clio.Identification, opts *scanOptions, userInput string) error {
writer, err := opts.SBOMWriter()
if err != nil {
return err
}
src, err := getSource(&opts.Catalog, userInput)
sources := opts.From
if len(sources) == 0 {
// extract a scheme if it matches any provider tag; this is a holdover for compatibility, using the --from flag is recommended
explicitSource, newUserInput := stereoscope.ExtractSchemeSource(userInput, allSourceProviderTags()...)
if explicitSource != "" {
sources = append(sources, explicitSource)
userInput = newUserInput
}
}
src, err := getSource(ctx, &opts.Catalog, userInput, sources...)
if err != nil {
return err
@@ -199,23 +211,21 @@ func runScan(ctx context.Context, id clio.Identification, opts *scanOptions, use
return nil
}
func getSource(opts *options.Catalog, userInput string, filters ...func(*source.Detection) error) (source.Source, error) {
detection, err := source.Detect(
userInput,
source.DetectConfig{
DefaultImageSource: opts.Source.Image.DefaultPullSource,
},
)
if err != nil {
return nil, fmt.Errorf("could not deteremine source: %w", err)
}
for _, filter := range filters {
if err := filter(detection); err != nil {
return nil, err
}
}
func getSource(ctx context.Context, opts *options.Catalog, userInput string, sources ...string) (source.Source, error) {
cfg := syft.DefaultGetSourceConfig().
WithRegistryOptions(opts.Registry.ToOptions()).
WithAlias(source.Alias{
Name: opts.Source.Name,
Version: opts.Source.Version,
}).
WithExcludeConfig(source.ExcludeConfig{
Paths: opts.Exclusions,
}).
WithBasePath(opts.Source.BasePath).
WithSources(sources...).
WithDefaultImagePullSource(opts.Source.Image.DefaultPullSource)
var err error
var platform *image.Platform
if opts.Platform != "" {
@@ -223,29 +233,22 @@ func getSource(opts *options.Catalog, userInput string, filters ...func(*source.
if err != nil {
return nil, fmt.Errorf("invalid platform: %w", err)
}
cfg = cfg.WithPlatform(platform)
}
hashers, err := file.Hashers(opts.Source.File.Digests...)
if opts.Source.File.Digests != nil {
hashers, err := file.Hashers(opts.Source.File.Digests...)
if err != nil {
return nil, fmt.Errorf("invalid hash algorithm: %w", err)
}
cfg = cfg.WithDigestAlgorithms(hashers...)
}
src, err := syft.GetSource(ctx, userInput, cfg)
if err != nil {
return nil, fmt.Errorf("invalid hash algorithm: %w", err)
return nil, fmt.Errorf("could not determine source: %w", err)
}
src, err := detection.NewSource(
source.DetectionSourceConfig{
Alias: source.Alias{
Name: opts.Source.Name,
Version: opts.Source.Version,
},
RegistryOptions: opts.Registry.ToOptions(),
Platform: platform,
Exclude: source.ExcludeConfig{
Paths: opts.Exclusions,
},
DigestAlgorithms: hashers,
BasePath: opts.Source.BasePath,
},
)
if err != nil {
if userInput == "power-user" {
bus.Notify("Note: the 'power-user' command has been removed.")
@@ -445,3 +448,7 @@ func getHintPhrase(expErr task.ErrInvalidExpression) string {
func trimOperation(x string) string {
return strings.TrimLeft(x, "+-")
}
func allSourceProviderTags() []string {
return collections.TaggedValueSet[source.Provider]{}.Join(sourceproviders.All("", nil)...).Tags()
}
+1 -1
View File
@@ -28,7 +28,7 @@ var latestAppVersionURL = struct {
}
func applicationUpdateCheck(id clio.Identification, check *options.UpdateCheck) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
return func(_ *cobra.Command, _ []string) error {
if check.CheckForAppUpdate {
checkForApplicationUpdate(id)
}
+15 -2
View File
@@ -46,6 +46,7 @@ type Catalog struct {
// configuration for the source (the subject being analyzed)
Registry registryConfig `yaml:"registry" json:"registry" mapstructure:"registry"`
From []string `yaml:"from" json:"from" mapstructure:"from"`
Platform string `yaml:"platform" json:"platform" mapstructure:"platform"`
Source sourceConfig `yaml:"source" json:"source" mapstructure:"source"`
Exclusions []string `yaml:"exclude" json:"exclude" mapstructure:"exclude"`
@@ -62,6 +63,7 @@ func DefaultCatalog() Catalog {
Scope: source.SquashedScope.String(),
Package: defaultPackageConfig(),
LinuxKernel: defaultLinuxKernelConfig(),
Golang: defaultGolangConfig(),
File: defaultFileConfig(),
Relationships: defaultRelationshipsConfig(),
Source: defaultSourceConfig(),
@@ -125,13 +127,19 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config {
IncludeUnindexedArchives: cfg.Package.SearchUnindexedArchives,
}
return pkgcataloging.Config{
Binary: binary.DefaultCatalogerConfig(),
Binary: binary.DefaultClassifierCatalogerConfig(),
Golang: golang.DefaultCatalogerConfig().
WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses).
WithLocalModCacheDir(cfg.Golang.LocalModCacheDir).
WithSearchRemoteLicenses(cfg.Golang.SearchRemoteLicenses).
WithProxy(cfg.Golang.Proxy).
WithNoProxy(cfg.Golang.NoProxy),
WithNoProxy(cfg.Golang.NoProxy).
WithMainModuleVersion(
golang.DefaultMainModuleVersionConfig().
WithFromContents(cfg.Golang.MainModuleVersion.FromContents).
WithFromBuildSettings(cfg.Golang.MainModuleVersion.FromBuildSettings).
WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags),
),
JavaScript: javascript.DefaultCatalogerConfig().
WithSearchRemoteLicenses(cfg.JavaScript.SearchRemoteLicenses).
WithNpmBaseURL(cfg.JavaScript.NpmBaseURL),
@@ -156,6 +164,9 @@ func (cfg *Catalog) AddFlags(flags clio.FlagSet) {
flags.StringVarP(&cfg.Scope, "scope", "s",
fmt.Sprintf("selection of layers to catalog, options=%v", validScopeValues))
flags.StringArrayVarP(&cfg.From, "from", "",
"specify the source behavior to use (e.g. docker, registry, oci-dir, ...)")
flags.StringVarP(&cfg.Platform, "platform", "",
"an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux')")
@@ -213,6 +224,8 @@ func (cfg *Catalog) PostLoad() error {
return out
}
cfg.From = flatten(cfg.From)
cfg.Catalogers = flatten(cfg.Catalogers)
cfg.DefaultCatalogers = flatten(cfg.DefaultCatalogers)
cfg.SelectCatalogers = flatten(cfg.SelectCatalogers)
+5 -3
View File
@@ -3,6 +3,7 @@ package options
import (
"github.com/anchore/clio"
"github.com/anchore/syft/syft/format"
"github.com/anchore/syft/syft/format/spdxtagvalue"
"github.com/anchore/syft/syft/sbom"
)
@@ -41,9 +42,10 @@ func (o Format) Encoders() ([]sbom.FormatEncoder, error) {
return format.EncodersConfig{
Template: o.Template.config(),
SyftJSON: o.SyftJSON.config(),
SPDXJSON: o.SPDXJSON.config(format.AllVersions), // we support multiple versions, not just a single version
CyclonedxJSON: o.CyclonedxJSON.config(format.AllVersions), // we support multiple versions, not just a single version
CyclonedxXML: o.CyclonedxXML.config(format.AllVersions), // we support multiple versions, not just a single version
SPDXJSON: o.SPDXJSON.config(format.AllVersions), // we support multiple versions, not just a single version
SPDXTagValue: spdxtagvalue.EncoderConfig{Version: format.AllVersions}, // we support multiple versions, not just a single version
CyclonedxJSON: o.CyclonedxJSON.config(format.AllVersions), // we support multiple versions, not just a single version
CyclonedxXML: o.CyclonedxXML.config(format.AllVersions), // we support multiple versions, not just a single version
}.Encoders()
}
+34 -5
View File
@@ -1,9 +1,38 @@
package options
import (
"strings"
"github.com/anchore/syft/syft/pkg/cataloger/golang"
)
type golangConfig struct {
SearchLocalModCacheLicenses bool `json:"search-local-mod-cache-licenses" yaml:"search-local-mod-cache-licenses" mapstructure:"search-local-mod-cache-licenses"`
LocalModCacheDir string `json:"local-mod-cache-dir" yaml:"local-mod-cache-dir" mapstructure:"local-mod-cache-dir"`
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
Proxy string `json:"proxy" yaml:"proxy" mapstructure:"proxy"`
NoProxy string `json:"no-proxy" yaml:"no-proxy" mapstructure:"no-proxy"`
SearchLocalModCacheLicenses bool `json:"search-local-mod-cache-licenses" yaml:"search-local-mod-cache-licenses" mapstructure:"search-local-mod-cache-licenses"`
LocalModCacheDir string `json:"local-mod-cache-dir" yaml:"local-mod-cache-dir" mapstructure:"local-mod-cache-dir"`
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
Proxy string `json:"proxy" yaml:"proxy" mapstructure:"proxy"`
NoProxy string `json:"no-proxy" yaml:"no-proxy" mapstructure:"no-proxy"`
MainModuleVersion golangMainModuleVersionConfig `json:"main-module-version" yaml:"main-module-version" mapstructure:"main-module-version"`
}
type golangMainModuleVersionConfig struct {
FromLDFlags bool `json:"from-ld-flags" yaml:"from-ld-flags" mapstructure:"from-ld-flags"`
FromContents bool `json:"from-contents" yaml:"from-contents" mapstructure:"from-contents"`
FromBuildSettings bool `json:"from-build-settings" yaml:"from-build-settings" mapstructure:"from-build-settings"`
}
func defaultGolangConfig() golangConfig {
def := golang.DefaultCatalogerConfig()
return golangConfig{
SearchLocalModCacheLicenses: def.SearchLocalModCacheLicenses,
LocalModCacheDir: def.LocalModCacheDir,
SearchRemoteLicenses: def.SearchRemoteLicenses,
Proxy: strings.Join(def.Proxies, ","),
NoProxy: strings.Join(def.NoProxy, ","),
MainModuleVersion: golangMainModuleVersionConfig{
FromLDFlags: def.MainModuleVersion.FromLDFlags,
FromContents: def.MainModuleVersion.FromContents,
FromBuildSettings: def.MainModuleVersion.FromBuildSettings,
},
}
}
+7 -4
View File
@@ -6,6 +6,8 @@ import (
"strings"
"github.com/scylladb/go-set/strset"
"github.com/anchore/syft/syft/source/sourceproviders"
)
type sourceConfig struct {
@@ -25,12 +27,13 @@ type imageSource struct {
}
func defaultSourceConfig() sourceConfig {
var digests []string
for _, alg := range sourceproviders.DefaultConfig().DigestAlgorithms {
digests = append(digests, alg.String())
}
return sourceConfig{
File: fileSource{
Digests: []string{"sha256"},
},
Image: imageSource{
DefaultPullSource: "",
Digests: digests,
},
}
}
@@ -452,4 +452,12 @@ var commonTestCases = []testCase{
"glibc": "2.34-210",
},
},
{
name: "find wordpress plugins",
pkgType: pkg.WordpressPluginPkg,
pkgLanguage: pkg.PHP,
pkgInfo: map[string]string{
"Akismet Anti-spam: Spam Protection": "5.3",
},
},
}
@@ -22,15 +22,11 @@ func BenchmarkImagePackageCatalogers(b *testing.B) {
tarPath := imagetest.GetFixtureImageTarPath(b, fixtureImageName)
// get the source object for the image
userInput := "docker-archive:" + tarPath
detection, err := source.Detect(userInput, source.DefaultDetectConfig())
require.NoError(b, err)
theSource, err := detection.NewSource(source.DefaultDetectionSourceConfig())
theSource, err := syft.GetSource(context.Background(), tarPath, syft.DefaultGetSourceConfig().WithSources("docker-archive"))
require.NoError(b, err)
b.Cleanup(func() {
theSource.Close()
require.NoError(b, theSource.Close())
})
// build the SBOM
@@ -123,7 +119,6 @@ func TestPkgCoverageImage(t *testing.T) {
}
t.Fatalf("unexpected package count: %d!=%d", pkgCount, len(c.pkgInfo))
}
})
}
@@ -211,7 +206,6 @@ func TestPkgCoverageDirectory(t *testing.T) {
}
t.Fatalf("unexpected package count: %d!=%d", actualPkgCount, len(test.pkgInfo))
}
})
}
@@ -249,7 +243,6 @@ func TestPkgCoverageImage_HasEvidence(t *testing.T) {
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
for a := range sbom.Artifacts.Packages.Enumerate(c.pkgType) {
assert.NotEmpty(t, a.Locations.ToSlice(), "package %q has no locations (type=%q)", a.Name, a.Type)
for _, l := range a.Locations.ToSlice() {
@@ -259,7 +252,6 @@ func TestPkgCoverageImage_HasEvidence(t *testing.T) {
}
}
}
})
}
@@ -279,7 +271,6 @@ func TestPkgCoverageDirectory_HasEvidence(t *testing.T) {
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
for a := range sbom.Artifacts.Packages.Enumerate(c.pkgType) {
assert.NotEmpty(t, a.Locations.ToSlice(), "package %q has no locations (type=%q)", a.Name, a.Type)
for _, l := range a.Locations.ToSlice() {
@@ -289,7 +280,6 @@ func TestPkgCoverageDirectory_HasEvidence(t *testing.T) {
}
}
}
})
}
@@ -31,7 +31,9 @@ func Test_packageCatalogerExports(t *testing.T) {
for pkg, expected := range expectAtLeast {
actual, ok := exports[pkg]
require.True(t, ok, pkg)
require.True(t, expected.IsSubset(actual.Names()), pkg)
if !assert.True(t, actual.Names().IsSubset(expected), pkg) {
t.Logf("missing: %s", strset.SymmetricDifference(expected, actual.Names()))
}
}
}
@@ -0,0 +1,17 @@
<?php
/**
* @package Akismet
*/
/*
Plugin Name:Akismet Anti-spam: Spam Protection
Plugin URI: https://akismet.com/
Description: Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. Akismet Anti-spam keeps your site protected even while you sleep. To get started: activate the Akismet plugin and then go to your Akismet Settings page to set up your API key.
Version: 5.3
Requires at least: 5.8
Requires PHP: 5.6.20
Author: Automattic - Anti-spam Team
Author URI: https://automattic.com/wordpress-plugins/
License: GPLv2 or later
Text Domain: akismet
*/
// rest of plugin's code ...
@@ -34,17 +34,13 @@ func catalogFixtureImageWithConfig(t *testing.T, fixtureImageName string, cfg *s
// get the fixture image tar file
imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
userInput := "docker-archive:" + tarPath
// get the source to build an SBOM against
detection, err := source.Detect(userInput, source.DefaultDetectConfig())
require.NoError(t, err)
theSource, err := detection.NewSource(source.DefaultDetectionSourceConfig())
theSource, err := syft.GetSource(context.Background(), tarPath, syft.DefaultGetSourceConfig().WithSources("docker-archive"))
require.NoError(t, err)
t.Cleanup(func() {
theSource.Close()
require.NoError(t, theSource.Close())
})
s, err := syft.CreateSBOM(context.Background(), theSource, cfg)
@@ -71,14 +67,10 @@ func catalogDirectoryWithConfig(t *testing.T, dir string, cfg *syft.CreateSBOMCo
cfg.CatalogerSelection = cfg.CatalogerSelection.WithDefaults(pkgcataloging.DirectoryTag)
// get the source to build an sbom against
userInput := "dir:" + dir
detection, err := source.Detect(userInput, source.DefaultDetectConfig())
require.NoError(t, err)
theSource, err := detection.NewSource(source.DefaultDetectionSourceConfig())
theSource, err := syft.GetSource(context.Background(), dir, syft.DefaultGetSourceConfig().WithSources("dir"))
require.NoError(t, err)
t.Cleanup(func() {
theSource.Close()
require.NoError(t, theSource.Close())
})
// build the SBOM
+1 -11
View File
@@ -44,17 +44,7 @@ func imageReference() string {
func getSource(input string) source.Source {
fmt.Println("detecting source type for input:", input, "...")
detection, err := source.Detect(input,
source.DetectConfig{
DefaultImageSource: "docker",
},
)
if err != nil {
panic(err)
}
src, err := detection.NewSource(source.DefaultDetectionSourceConfig())
src, err := syft.GetSource(context.Background(), input, nil)
if err != nil {
panic(err)
+1 -11
View File
@@ -37,17 +37,7 @@ func imageReference() string {
}
func getSource(input string) source.Source {
detection, err := source.Detect(input,
source.DetectConfig{
DefaultImageSource: "docker",
},
)
if err != nil {
panic(err)
}
src, err := detection.NewSource(source.DefaultDetectionSourceConfig())
src, err := syft.GetSource(context.Background(), input, nil)
if err != nil {
panic(err)
+68
View File
@@ -0,0 +1,68 @@
package main
import (
"context"
"encoding/json"
"os"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/cataloging/pkgcataloging"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
)
const defaultImage = "alpine:3.19"
func main() {
// automagically get a source.Source for arbitrary string input
src := getSource(imageReference())
// catalog the given source and return a SBOM
// let's explicitly use catalogers that are:
// - for installed software
// - used in the directory scan
sbom := getSBOM(src, pkgcataloging.InstalledTag, pkgcataloging.DirectoryTag)
// Show a basic catalogers and input configuration used
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(sbom.Descriptor.Configuration); err != nil {
panic(err)
}
}
func imageReference() string {
// read an image string reference from the command line or use a default
if len(os.Args) > 1 {
return os.Args[1]
}
return defaultImage
}
func getSource(input string) source.Source {
src, err := syft.GetSource(context.Background(), input, nil)
if err != nil {
panic(err)
}
return src
}
func getSBOM(src source.Source, defaultTags ...string) sbom.SBOM {
cfg := syft.DefaultCreateSBOMConfig().
WithCatalogerSelection(
// here you can sub-select, add, remove catalogers from the default selection...
// or replace the default selection entirely!
pkgcataloging.NewSelectionRequest().
WithDefaults(defaultTags...),
)
s, err := syft.CreateSBOM(context.Background(), src, cfg)
if err != nil {
panic(err)
}
return *s
}
+19 -10
View File
@@ -1,10 +1,15 @@
package main
import (
"context"
"encoding/json"
"os"
"github.com/anchore/go-collections"
"github.com/anchore/stereoscope"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/sourceproviders"
)
/*
@@ -28,18 +33,18 @@ import (
const defaultImage = "alpine:3.19"
func main() {
detection, err := source.Detect(
imageReference(),
source.DetectConfig{
DefaultImageSource: "docker",
},
)
userInput := imageReference()
if err != nil {
panic(err)
// parse the scheme against the known set of schemes
schemeSource, newUserInput := stereoscope.ExtractSchemeSource(userInput, allSourceTags()...)
// set up the GetSourceConfig
getSourceCfg := syft.DefaultGetSourceConfig()
if schemeSource != "" {
getSourceCfg = getSourceCfg.WithSources(schemeSource)
userInput = newUserInput
}
src, err := detection.NewSource(source.DefaultDetectionSourceConfig())
src, err := syft.GetSource(context.Background(), userInput, getSourceCfg)
if err != nil {
panic(err)
@@ -60,3 +65,7 @@ func imageReference() string {
}
return defaultImage
}
func allSourceTags() []string {
return collections.TaggedValueSet[source.Provider]{}.Join(sourceproviders.All("", nil)...).Tags()
}
+9 -14
View File
@@ -1,11 +1,13 @@
package main
import (
"context"
"encoding/json"
"os"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/syft/source"
"github.com/anchore/stereoscope"
"github.com/anchore/stereoscope/pkg/image/oci"
"github.com/anchore/syft/syft/source/stereoscopesource"
)
/*
@@ -16,22 +18,15 @@ import (
const defaultImage = "alpine:3.19"
func main() {
platform, err := image.NewPlatform("linux/amd64")
// using oci.Registry causes the lookup to always use the registry, there are several other "Source" options here
img, err := stereoscope.GetImageFromSource(context.Background(), imageReference(), oci.Registry, stereoscope.WithPlatform("linux/amd64"))
if err != nil {
panic(err)
}
src, err := source.NewFromStereoscopeImage(
source.StereoscopeImageConfig{
Reference: imageReference(),
From: image.OciRegistrySource, // always use the registry, there are several other "Source" options here
Platform: platform,
},
)
if err != nil {
panic(err)
}
src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
Reference: imageReference(),
})
// Show a basic description of the source to the screen
enc := json.NewEncoder(os.Stdout)
+19 -21
View File
@@ -9,14 +9,15 @@ require (
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/acobaugh/osrelease v0.1.0
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9
github.com/anchore/clio v0.0.0-20240131202212-9eba61247448
github.com/anchore/clio v0.0.0-20240209204744-cb94e40a4f65
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/packageurl-go v0.1.1-0.20240202171727-877e1747d426
github.com/anchore/stereoscope v0.0.2-0.20240202153536-bfa15e446f06
github.com/anchore/stereoscope v0.0.2-0.20240221144950-cf0e754f5b56
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
// we are hinting brotli to latest due to warning when installing archiver v3:
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
@@ -53,10 +54,11 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/mitchellh/mapstructure v1.5.0
github.com/moby/sys/mountinfo v0.7.1
github.com/olekukonko/tablewriter v0.0.5
github.com/opencontainers/go-digest v1.0.0
github.com/pelletier/go-toml v1.9.5
github.com/saferwall/pe v1.4.8
github.com/saferwall/pe v1.5.2
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
github.com/sanity-io/litter v1.5.5
github.com/sassoftware/go-rpmutils v0.3.0
@@ -75,16 +77,15 @@ require (
github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1
go.uber.org/goleak v1.3.0
golang.org/x/mod v0.15.0
golang.org/x/net v0.20.0
golang.org/x/net v0.21.0
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.28.0
modernc.org/sqlite v1.29.2
)
require (
dario.cat/mergo v1.0.0 // 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
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
@@ -136,13 +137,13 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
github.com/imdario/mergo v0.3.15 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
@@ -160,13 +161,13 @@ require (
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc3 // indirect
github.com/opencontainers/runc v1.1.12 // indirect
@@ -215,13 +216,13 @@ require (
go.opentelemetry.io/otel/trace v1.19.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/term v0.16.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.13.0 // indirect
golang.org/x/tools v0.17.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
@@ -229,15 +230,12 @@ require (
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.29.0 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.41.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)
retract (
+40 -50
View File
@@ -52,8 +52,8 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA=
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
@@ -93,10 +93,12 @@ github.com/anchore/archiver/v3 v3.5.2 h1:Bjemm2NzuRhmHy3m0lRe5tNoClB9A4zYyDV58Pa
github.com/anchore/archiver/v3 v3.5.2/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9 h1:p0ZIe0htYOX284Y4axJaGBvXHU0VCCzLN5Wf5XbKStU=
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9/go.mod h1:3ZsFB9tzW3vl4gEiUeuSOMDnwroWxIxJelOOHUp8dSw=
github.com/anchore/clio v0.0.0-20240131202212-9eba61247448 h1:ZgecmkxhH5im+9jPs7Ra1Thmv/p4IBDsoCFD6W8pENg=
github.com/anchore/clio v0.0.0-20240131202212-9eba61247448/go.mod h1:t5Mld8naKcG8RTPjW/2n7bfyBKFl1A6PvtXw+v64gK0=
github.com/anchore/clio v0.0.0-20240209204744-cb94e40a4f65 h1:u9XrEabKlGPsrmRvAER+kUKkwXiJfLyqGhmOTFsXjX4=
github.com/anchore/clio v0.0.0-20240209204744-cb94e40a4f65/go.mod h1:8Jr7CjmwFVcBPtkJdTpaAGHimoGJGfbExypjzOu87Og=
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b h1:L/djgY7ZbZ/38+wUtdkk398W3PIBJLkt1N8nU/7e47A=
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b/go.mod h1:TLcE0RE5+8oIx2/NPWem/dq1DeaMoC+fPEH7hoSzPLo=
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537 h1:GjNGuwK5jWjJMyVppBjYS54eOiiSNv4Ba869k4wh72Q=
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537/go.mod h1:1aiktV46ATCkuVg0O573ZrH56BUawTECPETbZyBcqT8=
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw=
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a/go.mod h1:ubLFmlsv8/DFUQrZwY5syT5/8Er3ugSr4rDFwHsE3hg=
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU=
@@ -109,8 +111,8 @@ github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZV
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
github.com/anchore/packageurl-go v0.1.1-0.20240202171727-877e1747d426 h1:agoiZchSf1Nnnos1azwIg5hk5Ao9TzZNBD9++AChGEg=
github.com/anchore/packageurl-go v0.1.1-0.20240202171727-877e1747d426/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
github.com/anchore/stereoscope v0.0.2-0.20240202153536-bfa15e446f06 h1:3NAS33Bqrw87wckTff6/yXYDL1h3Wm6OiqaR1kcvW10=
github.com/anchore/stereoscope v0.0.2-0.20240202153536-bfa15e446f06/go.mod h1:uydT2ful8TY7Hr1WH1V1ZecSq/2TqXpAsGkMiy7lxD0=
github.com/anchore/stereoscope v0.0.2-0.20240221144950-cf0e754f5b56 h1:iHvTXZA+qEozPGRRuW1Mv7r7w2fHeJdzWDx+YsSIbyg=
github.com/anchore/stereoscope v0.0.2-0.20240221144950-cf0e754f5b56/go.mod h1:evQiJMQG56Z7/L5uhA8kfhhjF6ESJUZzUH9ms6bQ2Co=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
@@ -438,6 +440,8 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
@@ -480,8 +484,6 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 h1:WdAeg/imY2JFPc/9CST4bZ80nNJbiBFCAdSZCSgrS5Y=
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953/go.mod h1:6o+UrvuZWc4UTyBhQf0LGjW9Ld7qJxLz/OqvSOWWlEc=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@@ -569,8 +571,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
@@ -593,6 +595,8 @@ github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKt
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
@@ -666,8 +670,8 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/saferwall/pe v1.4.8 h1:ey/L8FGBMrJ1Xh+Rltj1MAFPZ4LOQYGJqNa5B1Na6B0=
github.com/saferwall/pe v1.4.8/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
github.com/saferwall/pe v1.5.2 h1:h5lLtLsyxGHQ9dN6cd8EfeLEBEo5gdqJpkuw4o4vTMY=
github.com/saferwall/pe v1.5.2/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
@@ -857,8 +861,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -869,8 +873,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 h1:mchzmB1XO2pMaKFRqk/+MV3mgGG96aqaPXaMifQU47w=
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -948,8 +952,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -980,8 +984,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1061,15 +1065,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1145,8 +1149,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1339,34 +1343,20 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs=
modernc.org/libc v1.29.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
modernc.org/sqlite v1.29.2 h1:xgBSyA3gemwgP31PWFfFjtBorQNYpeypGdoSDjXhrgI=
modernc.org/sqlite v1.29.2/go.mod h1:hG41jCYxOAOoO6BRK66AdRlmOcDzXf7qnwlwjUIOqa0=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+2 -1
View File
@@ -694,6 +694,7 @@ main() (
set +u
if [ -z "${TEST_INSTALL_SH}" ]; then
set -u
exit $(main "$@")
main "$@"
exit $?
fi
set -u
+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.3"
JSONSchemaVersion = "16.0.4"
)
+64 -2
View File
@@ -1,9 +1,9 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at 2023-10-05 22:45:16.827263 -0400 EDT m=+0.138031521
// This file was generated by robots at 2024-02-09 10:57:33.980847 -0500 EST m=+0.165923154
// using data from https://spdx.org/licenses/licenses.json
package spdxlicense
const Version = "3.22"
const Version = "3.23"
var licenseIDs = map[string]string{
"0bsd": "0BSD",
@@ -13,6 +13,7 @@ var licenseIDs = map[string]string{
"adobe2006": "Adobe-2006",
"adobe2006.0": "Adobe-2006",
"adobe2006.0.0": "Adobe-2006",
"adobedisplaypostscript": "Adobe-Display-PostScript",
"adobeglyph": "Adobe-Glyph",
"adobeutopia": "Adobe-Utopia",
"adsl": "ADSL",
@@ -57,6 +58,7 @@ var licenseIDs = map[string]string{
"aladdin": "Aladdin",
"amdplpa": "AMDPLPA",
"aml": "AML",
"amlglslang": "AML-glslang",
"ampas": "AMPAS",
"antlrpd": "ANTLR-PD",
"antlrpdfallback": "ANTLR-PD-fallback",
@@ -108,6 +110,7 @@ var licenseIDs = map[string]string{
"baekmuk": "Baekmuk",
"bahyph": "Bahyph",
"barr": "Barr",
"bcryptsolardesigner": "bcrypt-Solar-Designer",
"beerware": "Beerware",
"bitstreamcharter": "Bitstream-Charter",
"bitstreamvera": "Bitstream-Vera",
@@ -122,6 +125,9 @@ var licenseIDs = map[string]string{
"blueoak1.0.0": "BlueOak-1.0.0",
"boehmgc": "Boehm-GC",
"borceux": "Borceux",
"briangladman2.0.0clause": "Brian-Gladman-2-Clause",
"briangladman2.0clause": "Brian-Gladman-2-Clause",
"briangladman2clause": "Brian-Gladman-2-Clause",
"briangladman3.0.0clause": "Brian-Gladman-3-Clause",
"briangladman3.0clause": "Brian-Gladman-3-Clause",
"briangladman3clause": "Brian-Gladman-3-Clause",
@@ -129,21 +135,25 @@ var licenseIDs = map[string]string{
"bsd1.0clause": "BSD-1-Clause",
"bsd1clause": "BSD-1-Clause",
"bsd2.0.0clause": "BSD-2-Clause",
"bsd2.0.0clausedarwin": "BSD-2-Clause-Darwin",
"bsd2.0.0clausefreebsd": "BSD-2-Clause-Views",
"bsd2.0.0clausenetbsd": "BSD-2-Clause",
"bsd2.0.0clausepatent": "BSD-2-Clause-Patent",
"bsd2.0.0clauseviews": "BSD-2-Clause-Views",
"bsd2.0clause": "BSD-2-Clause",
"bsd2.0clausedarwin": "BSD-2-Clause-Darwin",
"bsd2.0clausefreebsd": "BSD-2-Clause-Views",
"bsd2.0clausenetbsd": "BSD-2-Clause",
"bsd2.0clausepatent": "BSD-2-Clause-Patent",
"bsd2.0clauseviews": "BSD-2-Clause-Views",
"bsd2clause": "BSD-2-Clause",
"bsd2clausedarwin": "BSD-2-Clause-Darwin",
"bsd2clausefreebsd": "BSD-2-Clause-Views",
"bsd2clausenetbsd": "BSD-2-Clause",
"bsd2clausepatent": "BSD-2-Clause-Patent",
"bsd2clauseviews": "BSD-2-Clause-Views",
"bsd3.0.0clause": "BSD-3-Clause",
"bsd3.0.0clauseacpica": "BSD-3-Clause-acpica",
"bsd3.0.0clauseattribution": "BSD-3-Clause-Attribution",
"bsd3.0.0clauseclear": "BSD-3-Clause-Clear",
"bsd3.0.0clauseflex": "BSD-3-Clause-flex",
@@ -157,6 +167,7 @@ var licenseIDs = map[string]string{
"bsd3.0.0clauseopenmpi": "BSD-3-Clause-Open-MPI",
"bsd3.0.0clausesun": "BSD-3-Clause-Sun",
"bsd3.0clause": "BSD-3-Clause",
"bsd3.0clauseacpica": "BSD-3-Clause-acpica",
"bsd3.0clauseattribution": "BSD-3-Clause-Attribution",
"bsd3.0clauseclear": "BSD-3-Clause-Clear",
"bsd3.0clauseflex": "BSD-3-Clause-flex",
@@ -170,6 +181,7 @@ var licenseIDs = map[string]string{
"bsd3.0clauseopenmpi": "BSD-3-Clause-Open-MPI",
"bsd3.0clausesun": "BSD-3-Clause-Sun",
"bsd3clause": "BSD-3-Clause",
"bsd3clauseacpica": "BSD-3-Clause-acpica",
"bsd3clauseattribution": "BSD-3-Clause-Attribution",
"bsd3clauseclear": "BSD-3-Clause-Clear",
"bsd3clauseflex": "BSD-3-Clause-flex",
@@ -201,8 +213,12 @@ var licenseIDs = map[string]string{
"bsdattributionhpnddisclaimer": "BSD-Attribution-HPND-disclaimer",
"bsdinfernonettverk": "BSD-Inferno-Nettverk",
"bsdprotection": "BSD-Protection",
"bsdsourcebeginningfile": "BSD-Source-beginning-file",
"bsdsourcecode": "BSD-Source-Code",
"bsdsystemics": "BSD-Systemics",
"bsdsystemicsw3.0.0works": "BSD-Systemics-W3Works",
"bsdsystemicsw3.0works": "BSD-Systemics-W3Works",
"bsdsystemicsw3works": "BSD-Systemics-W3Works",
"bsl1": "BSL-1.0",
"bsl1.0": "BSL-1.0",
"bsl1.0.0": "BSL-1.0",
@@ -220,6 +236,7 @@ var licenseIDs = map[string]string{
"cal1.0combinedworkexception": "CAL-1.0-Combined-Work-Exception",
"cal1combinedworkexception": "CAL-1.0-Combined-Work-Exception",
"caldera": "Caldera",
"calderanopreamble": "Caldera-no-preamble",
"catosl1": "CATOSL-1.1",
"catosl1.1": "CATOSL-1.1",
"catosl1.1.0": "CATOSL-1.1",
@@ -241,16 +258,19 @@ var licenseIDs = map[string]string{
"ccby3.0": "CC-BY-3.0",
"ccby3.0.0": "CC-BY-3.0",
"ccby3.0.0at": "CC-BY-3.0-AT",
"ccby3.0.0au": "CC-BY-3.0-AU",
"ccby3.0.0de": "CC-BY-3.0-DE",
"ccby3.0.0igo": "CC-BY-3.0-IGO",
"ccby3.0.0nl": "CC-BY-3.0-NL",
"ccby3.0.0us": "CC-BY-3.0-US",
"ccby3.0at": "CC-BY-3.0-AT",
"ccby3.0au": "CC-BY-3.0-AU",
"ccby3.0de": "CC-BY-3.0-DE",
"ccby3.0igo": "CC-BY-3.0-IGO",
"ccby3.0nl": "CC-BY-3.0-NL",
"ccby3.0us": "CC-BY-3.0-US",
"ccby3at": "CC-BY-3.0-AT",
"ccby3au": "CC-BY-3.0-AU",
"ccby3de": "CC-BY-3.0-DE",
"ccby3igo": "CC-BY-3.0-IGO",
"ccby3nl": "CC-BY-3.0-NL",
@@ -420,6 +440,7 @@ var licenseIDs = map[string]string{
"clartistic": "ClArtistic",
"clips": "Clips",
"cmumach": "CMU-Mach",
"cmumachnodoc": "CMU-Mach-nodoc",
"cnrijython": "CNRI-Jython",
"cnripython": "CNRI-Python",
"cnripythongplcompatible": "CNRI-Python-GPL-Compatible",
@@ -456,6 +477,9 @@ var licenseIDs = map[string]string{
"cuda1.0": "C-UDA-1.0",
"cuda1.0.0": "C-UDA-1.0",
"curl": "curl",
"dec3.0.0clause": "DEC-3-Clause",
"dec3.0clause": "DEC-3-Clause",
"dec3clause": "DEC-3-Clause",
"dfsl1": "D-FSL-1.0",
"dfsl1.0": "D-FSL-1.0",
"dfsl1.0.0": "D-FSL-1.0",
@@ -471,6 +495,8 @@ var licenseIDs = map[string]string{
"drl1": "DRL-1.0",
"drl1.0": "DRL-1.0",
"drl1.0.0": "DRL-1.0",
"drl1.1": "DRL-1.1",
"drl1.1.0": "DRL-1.1",
"dsdp": "DSDP",
"dtoa": "dtoa",
"dvipdfm": "dvipdfm",
@@ -526,12 +552,14 @@ var licenseIDs = map[string]string{
"freebsddoc": "FreeBSD-DOC",
"freeimage": "FreeImage",
"fsfap": "FSFAP",
"fsfapnowarrantydisclaimer": "FSFAP-no-warranty-disclaimer",
"fsful": "FSFUL",
"fsfullr": "FSFULLR",
"fsfullrwd": "FSFULLRWD",
"ftl": "FTL",
"furuseth": "Furuseth",
"fwlw": "fwlw",
"gcrdocs": "GCR-docs",
"gd": "GD",
"gfdl1": "GFDL-1.1-only",
"gfdl1+": "GFDL-1.1-or-later",
@@ -672,7 +700,9 @@ var licenseIDs = map[string]string{
"gsoap1.3.0b": "gSOAP-1.3b",
"gsoap1.3b": "gSOAP-1.3b",
"gsoap1b": "gSOAP-1.3b",
"gtkbook": "gtkbook",
"haskellreport": "HaskellReport",
"hdparm": "hdparm",
"hippocratic2": "Hippocratic-2.1",
"hippocratic2.1": "Hippocratic-2.1",
"hippocratic2.1.0": "Hippocratic-2.1",
@@ -688,8 +718,13 @@ var licenseIDs = map[string]string{
"hpnddocsell": "HPND-doc-sell",
"hpndexportus": "HPND-export-US",
"hpndexportusmodify": "HPND-export-US-modify",
"hpndfenneberglivingston": "HPND-Fenneberg-Livingston",
"hpndinriaimag": "HPND-INRIA-IMAG",
"hpndkevlinhenney": "HPND-Kevlin-Henney",
"hpndmarkuskuhn": "HPND-Markus-Kuhn",
"hpndmitdisclaimer": "HPND-MIT-disclaimer",
"hpndpbmplus": "HPND-Pbmplus",
"hpndsellmitdisclaimerxserver": "HPND-sell-MIT-disclaimer-xserver",
"hpndsellregexpr": "HPND-sell-regexpr",
"hpndsellvariant": "HPND-sell-variant",
"hpndsellvariantmitdisclaimer": "HPND-sell-variant-MIT-disclaimer",
@@ -719,6 +754,7 @@ var licenseIDs = map[string]string{
"ipl1.0": "IPL-1.0",
"ipl1.0.0": "IPL-1.0",
"isc": "ISC",
"iscveillard": "ISC-Veillard",
"jam": "Jam",
"jasper2": "JasPer-2.0",
"jasper2.0": "JasPer-2.0",
@@ -802,6 +838,7 @@ var licenseIDs = map[string]string{
"linuxmanpagescopyleftvar": "Linux-man-pages-copyleft-var",
"linuxopenib": "Linux-OpenIB",
"loop": "LOOP",
"lpddocument": "LPD-document",
"lpl1": "LPL-1.0",
"lpl1.0": "LPL-1.0",
"lpl1.0.0": "LPL-1.0",
@@ -828,7 +865,14 @@ var licenseIDs = map[string]string{
"lzmasdk9.22": "LZMA-SDK-9.22",
"lzmasdk9.22.0": "LZMA-SDK-9.22",
"lzmasdk9to9.20": "LZMA-SDK-9.11-to-9.20",
"mackerras3.0.0clause": "Mackerras-3-Clause",
"mackerras3.0.0clauseacknowledgment": "Mackerras-3-Clause-acknowledgment",
"mackerras3.0clause": "Mackerras-3-Clause",
"mackerras3.0clauseacknowledgment": "Mackerras-3-Clause-acknowledgment",
"mackerras3clause": "Mackerras-3-Clause",
"mackerras3clauseacknowledgment": "Mackerras-3-Clause-acknowledgment",
"magaz": "magaz",
"mailprio": "mailprio",
"makeindex": "MakeIndex",
"martinbirgmeier": "Martin-Birgmeier",
"mcpheeslideshow": "McPhee-slideshow",
@@ -1008,6 +1052,8 @@ var licenseIDs = map[string]string{
"openpbs2.3": "OpenPBS-2.3",
"openpbs2.3.0": "OpenPBS-2.3",
"openssl": "OpenSSL",
"opensslstandalone": "OpenSSL-standalone",
"openvision": "OpenVision",
"opl1": "OPL-1.0",
"opl1.0": "OPL-1.0",
"opl1.0.0": "OPL-1.0",
@@ -1051,6 +1097,7 @@ var licenseIDs = map[string]string{
"php3.0.0": "PHP-3.0",
"php3.01": "PHP-3.01",
"php3.01.0": "PHP-3.01",
"pixar": "Pixar",
"plexus": "Plexus",
"pnmstitch": "pnmstitch",
"polyformnoncommercial1": "PolyForm-Noncommercial-1.0.0",
@@ -1077,6 +1124,7 @@ var licenseIDs = map[string]string{
"qpl1.0.0inria2004": "QPL-1.0-INRIA-2004",
"qpl1.0inria2004": "QPL-1.0-INRIA-2004",
"qpl1inria2004": "QPL-1.0-INRIA-2004",
"radvd": "radvd",
"rdisc": "Rdisc",
"rhecos1": "RHeCos-1.1",
"rhecos1.1": "RHeCos-1.1",
@@ -1094,6 +1142,9 @@ var licenseIDs = map[string]string{
"ruby": "Ruby",
"saxpath": "Saxpath",
"saxpd": "SAX-PD",
"saxpd2": "SAX-PD-2.0",
"saxpd2.0": "SAX-PD-2.0",
"saxpd2.0.0": "SAX-PD-2.0",
"scea": "SCEA",
"schemereport": "SchemeReport",
"sendmail": "Sendmail",
@@ -1129,6 +1180,7 @@ var licenseIDs = map[string]string{
"smppl": "SMPPL",
"snia": "SNIA",
"snprintf": "snprintf",
"softsurfer": "softSurfer",
"soundex": "Soundex",
"spencer86": "Spencer-86",
"spencer86.0": "Spencer-86",
@@ -1145,6 +1197,7 @@ var licenseIDs = map[string]string{
"sshkeyscan": "ssh-keyscan",
"sshopenssh": "SSH-OpenSSH",
"sshshort": "SSH-short",
"ssleaystandalone": "SSLeay-standalone",
"sspl1": "SSPL-1.0",
"sspl1.0": "SSPL-1.0",
"sspl1.0.0": "SSPL-1.0",
@@ -1152,6 +1205,7 @@ var licenseIDs = map[string]string{
"sugarcrm1": "SugarCRM-1.1.3",
"sugarcrm1.1": "SugarCRM-1.1.3",
"sugarcrm1.1.3": "SugarCRM-1.1.3",
"sunppp": "Sun-PPP",
"sunpro": "SunPro",
"swl": "SWL",
"swrule": "swrule",
@@ -1162,6 +1216,9 @@ var licenseIDs = map[string]string{
"tcl": "TCL",
"tcpwrappers": "TCP-wrappers",
"termreadkey": "TermReadKey",
"tgppl1": "TGPPL-1.0",
"tgppl1.0": "TGPPL-1.0",
"tgppl1.0.0": "TGPPL-1.0",
"tmate": "TMate",
"torque1": "TORQUE-1.1",
"torque1.1": "TORQUE-1.1",
@@ -1184,6 +1241,10 @@ var licenseIDs = map[string]string{
"ucl1.0": "UCL-1.0",
"ucl1.0.0": "UCL-1.0",
"ulem": "ulem",
"umichmerit": "UMich-Merit",
"unicode3": "Unicode-3.0",
"unicode3.0": "Unicode-3.0",
"unicode3.0.0": "Unicode-3.0",
"unicodedfs2015": "Unicode-DFS-2015",
"unicodedfs2015.0": "Unicode-DFS-2015",
"unicodedfs2015.0.0": "Unicode-DFS-2015",
@@ -1236,6 +1297,7 @@ var licenseIDs = map[string]string{
"xfree861.1": "XFree86-1.1",
"xfree861.1.0": "XFree86-1.1",
"xinetd": "xinetd",
"xkeyboardconfigzinoviev": "xkeyboard-config-Zinoviev",
"xlock": "xlock",
"xnet": "Xnet",
"xpp": "xpp",
+1 -1
View File
@@ -11,7 +11,7 @@ import (
// TODO: add tui element here?
func NewEnvironmentTask() Task {
fn := func(ctx context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
fn := func(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
release := linux.IdentifyRelease(resolver)
if release != nil {
builder.SetLinuxDistribution(*release)
+1 -1
View File
@@ -108,7 +108,7 @@ func NewExecutableCatalogerTask(selection file.Selection, cfg executable.Config)
cat := executable.NewCataloger(cfg)
fn := func(ctx context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
fn := func(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
accessor := builder.(sbomsync.Accessor)
result, err := cat.Catalog(resolver)
+3 -1
View File
@@ -28,6 +28,7 @@ import (
"github.com/anchore/syft/syft/pkg/cataloger/rust"
sbomCataloger "github.com/anchore/syft/syft/pkg/cataloger/sbom"
"github.com/anchore/syft/syft/pkg/cataloger/swift"
"github.com/anchore/syft/syft/pkg/cataloger/wordpress"
)
//nolint:funlen
@@ -112,7 +113,7 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
// other package catalogers ///////////////////////////////////////////////////////////////////////////
newPackageTaskFactory(
func(cfg CatalogingFactoryConfig) pkg.Cataloger {
return binary.NewCataloger(cfg.PackagesConfig.Binary)
return binary.NewClassifierCataloger(cfg.PackagesConfig.Binary)
},
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "binary",
),
@@ -125,5 +126,6 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "linux", "kernel",
),
newSimplePackageTaskFactory(sbomCataloger.NewCataloger, "sbom"), // note: not evidence of installed packages
newSimplePackageTaskFactory(wordpress.NewWordpressPluginCataloger, pkgcataloging.DirectoryTag, pkgcataloging.ImageTag, "wordpress"),
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ func (s sourceIdentifierAdapter) ID() artifact.ID {
}
func NewRelationshipsTask(cfg cataloging.RelationshipsConfig, src source.Description) Task {
fn := func(ctx context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
fn := func(_ context.Context, _ file.Resolver, builder sbomsync.Builder) error {
relationship.Finalize(
builder,
cfg,
File diff suppressed because it is too large Load Diff
+6
View File
@@ -2242,6 +2242,12 @@
},
"type": "array"
},
"cpes": {
"items": {
"$ref": "#/$defs/CPE"
},
"type": "array"
},
"licenses": {
"items": {
"$ref": "#/$defs/License"
File diff suppressed because it is too large Load Diff
+21 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "anchore.io/schema/syft/json/16.0.3/document",
"$id": "anchore.io/schema/syft/json/16.0.4/document",
"$ref": "#/$defs/Document",
"$defs": {
"AlpmDbEntry": {
@@ -1493,6 +1493,9 @@
},
{
"$ref": "#/$defs/SwiftPackageManagerLockEntry"
},
{
"$ref": "#/$defs/WordpressPluginEntry"
}
]
}
@@ -2268,6 +2271,23 @@
"revision"
]
},
"WordpressPluginEntry": {
"properties": {
"pluginInstallDirectory": {
"type": "string"
},
"author": {
"type": "string"
},
"authorUri": {
"type": "string"
}
},
"type": "object",
"required": [
"pluginInstallDirectory"
]
},
"cpes": {
"items": {
"$ref": "#/$defs/CPE"
+3 -3
View File
@@ -10,7 +10,7 @@ import (
)
type Config struct {
Binary binary.CatalogerConfig `yaml:"binary" json:"binary" mapstructure:"binary"`
Binary binary.ClassifierCatalogerConfig `yaml:"binary" json:"binary" mapstructure:"binary"`
Golang golang.CatalogerConfig `yaml:"golang" json:"golang" mapstructure:"golang"`
JavaArchive java.ArchiveCatalogerConfig `yaml:"java-archive" json:"java-archive" mapstructure:"java-archive"`
JavaScript javascript.CatalogerConfig `yaml:"javascript" json:"javascript" mapstructure:"javascript"`
@@ -20,7 +20,7 @@ type Config struct {
func DefaultConfig() Config {
return Config{
Binary: binary.DefaultCatalogerConfig(),
Binary: binary.DefaultClassifierCatalogerConfig(),
Golang: golang.DefaultCatalogerConfig(),
LinuxKernel: kernel.DefaultLinuxKernelCatalogerConfig(),
Python: python.DefaultCatalogerConfig(),
@@ -28,7 +28,7 @@ func DefaultConfig() Config {
}
}
func (c Config) WithBinaryConfig(cfg binary.CatalogerConfig) Config {
func (c Config) WithBinaryConfig(cfg binary.ClassifierCatalogerConfig) Config {
c.Binary = cfg
return c
}
+28 -2
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"runtime/debug"
"strings"
"github.com/anchore/syft/internal/task"
@@ -44,9 +45,34 @@ func DefaultCreateSBOMConfig() *CreateSBOMConfig {
Files: filecataloging.DefaultConfig(),
Parallelism: 1,
packageTaskFactories: task.DefaultPackageTaskFactories(),
// library consumers are free to override the tool values to fit their needs, however, we have some sane defaults
// to ensure that SBOMs generated don't have missing tool metadata.
ToolName: "syft",
ToolVersion: syftVersion(),
}
}
func syftVersion() string {
// extract the syft version from the go module info from the current binary that is running. This is useful for
// library consumers to at least encode the version of syft that was used to generate the SBOM. Note: we don't
// use the version info from main because it's baked in with ldflags, which we don't control for library consumers.
// This approach won't work in all cases though, such as when the binary is stripped of the buildinfo section.
buildInfo, ok := debug.ReadBuildInfo()
if !ok {
return ""
}
for _, d := range buildInfo.Deps {
if d.Path == "github.com/anchore/syft" && d.Version != "(devel)" {
return d.Version
}
}
return ""
}
// WithTool allows for setting the specific name, version, and any additional configuration that is not captured
// in the syft default API configuration. This could cover inputs for catalogers that were user-provided, thus,
// is not visible to the syft API, but would be useful to see in the SBOM output.
@@ -319,9 +345,9 @@ func (c *CreateSBOMConfig) Create(ctx context.Context, src source.Source) (*sbom
func findDefaultTag(src source.Description) (string, error) {
switch m := src.Metadata.(type) {
case source.StereoscopeImageSourceMetadata:
case source.ImageMetadata:
return pkgcataloging.ImageTag, nil
case source.FileSourceMetadata, source.DirectorySourceMetadata:
case source.FileMetadata, source.DirectoryMetadata:
return pkgcataloging.DirectoryTag, nil
default:
return "", fmt.Errorf("unable to determine default cataloger tag for source type=%T", m)
+6 -6
View File
@@ -62,15 +62,15 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
}
imgSrc := source.Description{
Metadata: source.StereoscopeImageSourceMetadata{},
Metadata: source.ImageMetadata{},
}
dirSrc := source.Description{
Metadata: source.DirectorySourceMetadata{},
Metadata: source.DirectoryMetadata{},
}
fileSrc := source.Description{
Metadata: source.FileSourceMetadata{},
Metadata: source.FileMetadata{},
}
tests := []struct {
@@ -437,21 +437,21 @@ func Test_findDefaultTag(t *testing.T) {
{
name: "image",
src: source.Description{
Metadata: source.StereoscopeImageSourceMetadata{},
Metadata: source.ImageMetadata{},
},
want: pkgcataloging.ImageTag,
},
{
name: "directory",
src: source.Description{
Metadata: source.DirectorySourceMetadata{},
Metadata: source.DirectoryMetadata{},
},
want: pkgcataloging.DirectoryTag,
},
{
name: "file",
src: source.Description{
Metadata: source.FileSourceMetadata{},
Metadata: source.FileMetadata{},
},
want: pkgcataloging.DirectoryTag, // not a mistake...
},
+16 -6
View File
@@ -66,7 +66,15 @@ func (i *Cataloger) Catalog(resolver file.Resolver) (map[file.Coordinates]file.E
log.WithFields("error", err).Warnf("unable to get file contents for %q", loc.RealPath)
continue
}
exec, err := processExecutable(loc, reader.(unionreader.UnionReader))
uReader, err := unionreader.GetUnionReader(reader)
if err != nil {
// TODO: known-unknowns
log.WithFields("error", err).Warnf("unable to get union reader for %q", loc.RealPath)
continue
}
exec, err := processExecutable(loc, uReader)
if err != nil {
log.WithFields("error", err).Warnf("unable to process executable %q", loc.RealPath)
}
@@ -149,7 +157,7 @@ func processExecutable(loc file.Location, reader unionreader.UnionReader) (*file
securityFeatures, err := findSecurityFeatures(format, reader)
if err != nil {
log.WithFields("error", err).Warnf("unable to determine security features for %q", loc.RealPath)
log.WithFields("error", err).Tracef("unable to determine security features for %q", loc.RealPath)
return nil, nil
}
@@ -228,10 +236,12 @@ func findSecurityFeatures(format file.ExecutableFormat, reader unionreader.Union
switch format { //nolint: gocritic
case file.ELF:
return findELFSecurityFeatures(reader) //nolint: gocritic
// case file.PE:
// return findPESecurityFeatures(reader)
// case file.MachO:
// return findMachOSecurityFeatures(reader)
case file.PE:
// return findPESecurityFeatures(reader)
return nil, nil
case file.MachO:
// return findMachOSecurityFeatures(reader)
return nil, nil
}
return nil, fmt.Errorf("unsupported executable format: %q", format)
}
+3 -3
View File
@@ -45,7 +45,7 @@ func hasAnyDynamicSymbols(file *elf.File, symbolNames ...string) *bool {
dynSyms, err := file.DynamicSymbols()
if err != nil {
// TODO: known-unknowns
log.WithFields("error", err).Warn("unable to read dynamic symbols from elf file")
log.WithFields("error", err).Trace("unable to read dynamic symbols from elf file")
return nil
}
@@ -112,7 +112,7 @@ func hasElfDynFlag(f *elf.File, flag elf.DynFlag) bool {
vals, err := f.DynValue(elf.DT_FLAGS)
if err != nil {
// TODO: known-unknowns
log.WithFields("error", err).Warn("unable to read DT_FLAGS from elf file")
log.WithFields("error", err).Trace("unable to read DT_FLAGS from elf file")
return false
}
for _, val := range vals {
@@ -127,7 +127,7 @@ func hasElfDynFlag1(f *elf.File, flag elf.DynFlag1) bool {
vals, err := f.DynValue(elf.DT_FLAGS_1)
if err != nil {
// TODO: known-unknowns
log.WithFields("error", err).Warn("unable to read DT_FLAGS_1 from elf file")
log.WithFields("error", err).Trace("unable to read DT_FLAGS_1 from elf file")
return false
}
for _, val := range vals {
@@ -17,6 +17,8 @@ import (
intFile "github.com/anchore/syft/internal/file"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/directorysource"
"github.com/anchore/syft/syft/source/stereoscopesource"
)
func testDigests(t testing.TB, root string, files []string, hashes ...crypto.Hash) map[file.Coordinates][]file.Digest {
@@ -77,7 +79,7 @@ func TestDigestsCataloger(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
c := NewCataloger(test.digests)
src, err := source.NewFromDirectoryPath("test-fixtures/last/")
src, err := directorysource.NewFromPath("test-fixtures/last/")
require.NoError(t, err)
resolver, err := src.FileResolver(source.SquashedScope)
@@ -96,10 +98,9 @@ func TestDigestsCataloger_MixFileTypes(t *testing.T) {
img := imagetest.GetFixtureImage(t, "docker-archive", testImage)
src, err := source.NewFromStereoscopeImageObject(img, testImage, nil)
if err != nil {
t.Fatalf("could not create source: %+v", err)
}
src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
Reference: testImage,
})
resolver, err := src.FileResolver(source.SquashedScope)
if err != nil {
@@ -169,8 +170,9 @@ func TestFileDigestCataloger_GivenCoordinates(t *testing.T) {
c := NewCataloger([]crypto.Hash{crypto.SHA256})
src, err := source.NewFromStereoscopeImageObject(img, testImage, nil)
require.NoError(t, err)
src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
Reference: testImage,
})
resolver, err := src.FileResolver(source.SquashedScope)
require.NoError(t, err)
@@ -12,6 +12,7 @@ import (
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/stereoscopesource"
)
func TestFileMetadataCataloger(t *testing.T) {
@@ -21,8 +22,9 @@ func TestFileMetadataCataloger(t *testing.T) {
c := NewCataloger()
src, err := source.NewFromStereoscopeImageObject(img, testImage, nil)
require.NoError(t, err)
src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
Reference: testImage,
})
resolver, err := src.FileResolver(source.SquashedScope)
require.NoError(t, err)
@@ -159,8 +161,9 @@ func TestFileMetadataCataloger_GivenCoordinates(t *testing.T) {
c := NewCataloger()
src, err := source.NewFromStereoscopeImageObject(img, testImage, nil)
require.NoError(t, err)
src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
Reference: testImage,
})
resolver, err := src.FileResolver(source.SquashedScope)
require.NoError(t, err)
@@ -12,6 +12,8 @@ import (
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/directorysource"
"github.com/anchore/syft/syft/source/stereoscopesource"
)
func Test_allRegularFiles(t *testing.T) {
@@ -28,8 +30,9 @@ func Test_allRegularFiles(t *testing.T) {
img := imagetest.GetFixtureImage(t, "docker-archive", testImage)
s, err := source.NewFromStereoscopeImageObject(img, testImage, nil)
require.NoError(t, err)
s := stereoscopesource.New(img, stereoscopesource.ImageConfig{
Reference: testImage,
})
r, err := s.FileResolver(source.SquashedScope)
require.NoError(t, err)
@@ -42,7 +45,7 @@ func Test_allRegularFiles(t *testing.T) {
{
name: "directory",
setup: func() file.Resolver {
s, err := source.NewFromDirectoryPath("test-fixtures/symlinked-root/nested/link-root")
s, err := directorysource.NewFromPath("test-fixtures/symlinked-root/nested/link-root")
require.NoError(t, err)
r, err := s.FileResolver(source.SquashedScope)
require.NoError(t, err)
@@ -1,6 +1,7 @@
package cyclonedxhelpers
import (
"fmt"
"slices"
"strings"
"time"
@@ -84,8 +85,9 @@ func toOSComponent(distro *linux.Release) []cyclonedx.Component {
}
return []cyclonedx.Component{
{
Type: cyclonedx.ComponentTypeOS,
// FIXME is it idiomatic to be using SWID here for specific name and version information?
BOMRef: toOSBomRef(distro.ID, distro.VersionID),
Type: cyclonedx.ComponentTypeOS,
// is it idiomatic to be using SWID here for specific name and version information?
SWID: &cyclonedx.SWID{
TagID: distro.ID,
Name: distro.ID,
@@ -94,7 +96,7 @@ func toOSComponent(distro *linux.Release) []cyclonedx.Component {
Description: distro.PrettyName,
Name: distro.ID,
Version: distro.VersionID,
// TODO should we add a PURL?
// should we add a PURL?
CPE: formatCPE(distro.CPEName),
ExternalReferences: eRefs,
Properties: properties,
@@ -102,6 +104,16 @@ func toOSComponent(distro *linux.Release) []cyclonedx.Component {
}
}
func toOSBomRef(name string, version string) string {
if name == "" {
return "os:unknown"
}
if version == "" {
return fmt.Sprintf("os:%s", name)
}
return fmt.Sprintf("os:%s@%s", name, version)
}
func formatCPE(cpeString string) string {
c, err := cpe.NewAttributes(cpeString)
if err != nil {
@@ -196,7 +208,7 @@ func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependenc
}
func toBomProperties(srcMetadata source.Description) *[]cyclonedx.Property {
metadata, ok := srcMetadata.Metadata.(source.StereoscopeImageSourceMetadata)
metadata, ok := srcMetadata.Metadata.(source.ImageMetadata)
if ok {
props := helpers.EncodeProperties(metadata.Labels, "syft:image:labels")
return &props
@@ -208,7 +220,7 @@ func toBomDescriptorComponent(srcMetadata source.Description) *cyclonedx.Compone
name := srcMetadata.Name
version := srcMetadata.Version
switch metadata := srcMetadata.Metadata.(type) {
case source.StereoscopeImageSourceMetadata:
case source.ImageMetadata:
if name == "" {
name = metadata.UserInput
}
@@ -225,7 +237,7 @@ func toBomDescriptorComponent(srcMetadata source.Description) *cyclonedx.Compone
Name: name,
Version: version,
}
case source.DirectorySourceMetadata:
case source.DirectoryMetadata:
if name == "" {
name = metadata.Path
}
@@ -240,7 +252,7 @@ func toBomDescriptorComponent(srcMetadata source.Description) *cyclonedx.Compone
Name: name,
Version: version,
}
case source.FileSourceMetadata:
case source.FileMetadata:
if name == "" {
name = metadata.Path
}
@@ -11,6 +11,7 @@ import (
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/format/internal/cyclonedxutil/helpers"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
@@ -159,7 +160,7 @@ func Test_toBomDescriptor(t *testing.T) {
name: "test-image",
version: "1.0.0",
srcMetadata: source.Description{
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
Labels: map[string]string{
"key1": "value1",
},
@@ -234,3 +235,89 @@ func Test_toBomDescriptor(t *testing.T) {
})
}
}
func Test_toOsComponent(t *testing.T) {
tests := []struct {
name string
release linux.Release
expected cyclonedx.Component
}{
{
name: "basic os component",
release: linux.Release{
ID: "myLinux",
VersionID: "myVersion",
},
expected: cyclonedx.Component{
BOMRef: "os:myLinux@myVersion",
Type: cyclonedx.ComponentTypeOS,
Name: "myLinux",
Version: "myVersion",
SWID: &cyclonedx.SWID{
TagID: "myLinux",
Name: "myLinux",
Version: "myVersion",
},
Properties: &[]cyclonedx.Property{
{
Name: "syft:distro:id",
Value: "myLinux",
},
{
Name: "syft:distro:versionID",
Value: "myVersion",
},
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
gotSlice := toOSComponent(&test.release)
require.Len(t, gotSlice, 1)
got := gotSlice[0]
require.Equal(t, test.expected, got)
})
}
}
func Test_toOSBomRef(t *testing.T) {
tests := []struct {
name string
osName string
osVersion string
expected string
}{
{
name: "no name or version specified",
osName: "",
osVersion: "",
expected: "os:unknown",
},
{
name: "no version specified",
osName: "my-name",
osVersion: "",
expected: "os:my-name",
},
{
name: "no name specified",
osName: "",
osVersion: "my-version",
expected: "os:unknown",
},
{
name: "both name and version specified",
osName: "my-name",
osVersion: "my-version",
expected: "os:my-name@my-version",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := toOSBomRef(test.osName, test.osVersion)
require.Equal(t, test.expected, got)
})
}
}
@@ -181,7 +181,7 @@ func toRootPackage(s source.Description) *spdx.Package {
purpose := ""
var checksums []spdx.Checksum
switch m := s.Metadata.(type) {
case source.StereoscopeImageSourceMetadata:
case source.ImageMetadata:
prefix = prefixImage
purpose = spdxPrimaryPurposeContainer
@@ -211,11 +211,11 @@ func toRootPackage(s source.Description) *spdx.Package {
}
}
case source.DirectorySourceMetadata:
case source.DirectoryMetadata:
prefix = prefixDirectory
purpose = spdxPrimaryPurposeFile
case source.FileSourceMetadata:
case source.FileMetadata:
prefix = prefixFile
purpose = spdxPrimaryPurposeFile
@@ -35,7 +35,7 @@ func Test_toFormatModel(t *testing.T) {
Source: source.Description{
Name: "alpine",
Version: "sha256:d34db33f",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "alpine:latest",
ManifestDigest: "sha256:d34db33f",
},
@@ -106,7 +106,7 @@ func Test_toFormatModel(t *testing.T) {
in: sbom.SBOM{
Source: source.Description{
Name: "some/directory",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/directory",
},
},
@@ -170,7 +170,7 @@ func Test_toFormatModel(t *testing.T) {
Source: source.Description{
Name: "path/to/some.file",
Version: "sha256:d34db33f",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "path/to/some.file",
Digests: []file.Digest{
{
@@ -146,7 +146,7 @@ func containerSource(p *spdx.Package) source.Description {
ID: id,
Name: p.PackageName,
Version: p.PackageVersion,
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: container,
ID: id,
Layers: nil, // TODO handle formats with nested layer packages like Tern and K8s BOM tool
@@ -187,7 +187,7 @@ func fileSource(p *spdx.Package) source.Description {
func fileSourceMetadata(p *spdx.Package) (any, string) {
version := p.PackageVersion
m := source.FileSourceMetadata{
m := source.FileMetadata{
Path: p.PackageName,
}
// if this is a Syft SBOM, we might have output a digest as the version
@@ -206,7 +206,7 @@ func fileSourceMetadata(p *spdx.Package) (any, string) {
}
func directorySourceMetadata(p *spdx.Package) (any, string) {
return source.DirectorySourceMetadata{
return source.DirectoryMetadata{
Path: p.PackageName,
Base: "",
}, p.PackageVersion
@@ -229,15 +229,15 @@ func extractSourceFromNamespace(ns string) source.Description {
switch p {
case helpers.InputFile:
return source.Description{
Metadata: source.FileSourceMetadata{},
Metadata: source.FileMetadata{},
}
case helpers.InputImage:
return source.Description{
Metadata: source.StereoscopeImageSourceMetadata{},
Metadata: source.ImageMetadata{},
}
case helpers.InputDirectory:
return source.Description{
Metadata: source.DirectorySourceMetadata{},
Metadata: source.DirectoryMetadata{},
}
}
}
@@ -199,15 +199,15 @@ func TestExtractSourceFromNamespaces(t *testing.T) {
}{
{
namespace: "https://anchore.com/syft/file/d42b01d0-7325-409b-b03f-74082935c4d3",
expected: source.FileSourceMetadata{},
expected: source.FileMetadata{},
},
{
namespace: "https://anchore.com/syft/image/d42b01d0-7325-409b-b03f-74082935c4d3",
expected: source.StereoscopeImageSourceMetadata{},
expected: source.ImageMetadata{},
},
{
namespace: "https://anchore.com/syft/dir/d42b01d0-7325-409b-b03f-74082935c4d3",
expected: source.DirectorySourceMetadata{},
expected: source.DirectoryMetadata{},
},
{
namespace: "https://another-host/blob/123",
@@ -460,7 +460,7 @@ func Test_convertToAndFromFormat(t *testing.T) {
name: "image source",
source: source.Description{
ID: "DocumentRoot-Image-some-image",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
ID: "DocumentRoot-Image-some-image",
UserInput: "some-image:some-tag",
ManifestDigest: "sha256:ab8b83234bc28f28d8e",
@@ -476,7 +476,7 @@ func Test_convertToAndFromFormat(t *testing.T) {
source: source.Description{
ID: "DocumentRoot-Directory-.",
Name: ".",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: ".",
},
},
@@ -488,7 +488,7 @@ func Test_convertToAndFromFormat(t *testing.T) {
source: source.Description{
ID: "DocumentRoot-Directory-my-app",
Name: "my-app",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "my-app",
},
},
@@ -499,7 +499,7 @@ func Test_convertToAndFromFormat(t *testing.T) {
name: "file source",
source: source.Description{
ID: "DocumentRoot-File-my-app.exe",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "my-app.exe",
Digests: []file.Digest{
{
@@ -91,6 +91,7 @@
]
},
{
"bom-ref":"redacted",
"type": "operating-system",
"name": "debian",
"version": "1.2.3",
@@ -100,6 +100,7 @@
]
},
{
"bom-ref":"redacted",
"type": "operating-system",
"name": "debian",
"version": "1.2.3",
@@ -47,7 +47,7 @@
<property name="syft:metadata:installedSize">0</property>
</properties>
</component>
<component type="operating-system">
<component bom-ref="redacted" type="operating-system">
<name>debian</name>
<version>1.2.3</version>
<description>debian</description>
@@ -50,7 +50,7 @@
<property name="syft:metadata:installedSize">0</property>
</properties>
</component>
<component type="operating-system">
<component bom-ref="redacted" type="operating-system">
<name>debian</name>
<version>1.2.3</version>
<description>debian</description>
+3 -3
View File
@@ -116,16 +116,16 @@ func toPath(s source.Description, p pkg.Package) string {
}
packagePath = strings.TrimPrefix(packagePath, "/")
switch metadata := s.Metadata.(type) {
case source.StereoscopeImageSourceMetadata:
case source.ImageMetadata:
image := strings.ReplaceAll(metadata.UserInput, ":/", "//")
return fmt.Sprintf("%s:/%s", image, packagePath)
case source.FileSourceMetadata:
case source.FileMetadata:
path := trimRelative(metadata.Path)
if isArchive(metadata.Path) {
return fmt.Sprintf("%s:/%s", path, packagePath)
}
return path
case source.DirectorySourceMetadata:
case source.DirectoryMetadata:
path := trimRelative(metadata.Path)
if path != "" {
return fmt.Sprintf("%s/%s", path, packagePath)
@@ -22,7 +22,7 @@ func sbomFixture() sbom.SBOM {
Name: "syft",
},
Source: source.Description{
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "ubuntu:18.04",
Architecture: "amd64",
},
@@ -150,27 +150,27 @@ func Test_toGithubModel(t *testing.T) {
},
{
name: "current directory",
metadata: source.DirectorySourceMetadata{Path: "."},
metadata: source.DirectoryMetadata{Path: "."},
testPath: "etc",
},
{
name: "relative directory",
metadata: source.DirectorySourceMetadata{Path: "./artifacts"},
metadata: source.DirectoryMetadata{Path: "./artifacts"},
testPath: "artifacts/etc",
},
{
name: "absolute directory",
metadata: source.DirectorySourceMetadata{Path: "/artifacts"},
metadata: source.DirectoryMetadata{Path: "/artifacts"},
testPath: "/artifacts/etc",
},
{
name: "file",
metadata: source.FileSourceMetadata{Path: "./executable"},
metadata: source.FileMetadata{Path: "./executable"},
testPath: "executable",
},
{
name: "archive",
metadata: source.FileSourceMetadata{Path: "./archive.tar.gz"},
metadata: source.FileMetadata{Path: "./archive.tar.gz"},
testPath: "archive.tar.gz:/etc",
},
}
@@ -222,7 +222,7 @@ func extractComponents(meta *cyclonedx.Metadata) source.Description {
ID: "",
// TODO: can we decode alias name-version somehow? (it isn't be encoded in the first place yet)
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: c.Name,
ID: c.BOMRef,
ManifestDigest: c.Version,
@@ -235,7 +235,7 @@ func extractComponents(meta *cyclonedx.Metadata) source.Description {
// TODO: this is lossy... we can't know if this is a file or a directory
return source.Description{
ID: "",
Metadata: source.FileSourceMetadata{Path: c.Name},
Metadata: source.FileMetadata{Path: c.Name},
}
}
return source.Description{}
@@ -10,11 +10,11 @@ func DocumentName(src source.Description) string {
}
switch metadata := src.Metadata.(type) {
case source.StereoscopeImageSourceMetadata:
case source.ImageMetadata:
return metadata.UserInput
case source.DirectorySourceMetadata:
case source.DirectoryMetadata:
return metadata.Path
case source.FileSourceMetadata:
case source.FileMetadata:
return metadata.Path
default:
return "unknown"
@@ -23,7 +23,7 @@ func Test_DocumentName(t *testing.T) {
{
name: "image",
srcMetadata: source.Description{
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "image-repo/name:tag",
ID: "id",
ManifestDigest: "digest",
@@ -34,14 +34,14 @@ func Test_DocumentName(t *testing.T) {
{
name: "directory",
srcMetadata: source.Description{
Metadata: source.DirectorySourceMetadata{Path: "some/path/to/place"},
Metadata: source.DirectoryMetadata{Path: "some/path/to/place"},
},
expected: "some/path/to/place",
},
{
name: "file",
srcMetadata: source.Description{
Metadata: source.FileSourceMetadata{Path: "some/path/to/place"},
Metadata: source.FileMetadata{Path: "some/path/to/place"},
},
expected: "some/path/to/place",
},
@@ -49,7 +49,7 @@ func Test_DocumentName(t *testing.T) {
name: "named",
srcMetadata: source.Description{
Name: "some/name",
Metadata: source.FileSourceMetadata{Path: "some/path/to/place"},
Metadata: source.FileMetadata{Path: "some/path/to/place"},
},
expected: "some/name",
},
@@ -27,11 +27,11 @@ func DocumentNamespace(name string, src source.Description, desc sbom.Descriptor
name = cleanName(name)
input := "unknown-source-type"
switch src.Metadata.(type) {
case source.StereoscopeImageSourceMetadata:
case source.ImageMetadata:
input = InputImage
case source.DirectorySourceMetadata:
case source.DirectoryMetadata:
input = InputDirectory
case source.FileSourceMetadata:
case source.FileMetadata:
input = InputFile
}
@@ -25,7 +25,7 @@ func Test_documentNamespace(t *testing.T) {
name: "image",
inputName: "my-name",
src: source.Description{
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "image-repo/name:tag",
ID: "id",
ManifestDigest: "digest",
@@ -37,7 +37,7 @@ func Test_documentNamespace(t *testing.T) {
name: "directory",
inputName: "my-name",
src: source.Description{
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path/to/place",
},
},
@@ -47,7 +47,7 @@ func Test_documentNamespace(t *testing.T) {
name: "file",
inputName: "my-name",
src: source.Description{
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "some/path/to/place",
},
},
@@ -60,6 +60,8 @@ func SourceInfo(p pkg.Package) string {
answer = "acquired package info from resolved Swift package manifest"
case pkg.GithubActionPkg, pkg.GithubActionWorkflowPkg:
answer = "acquired package info from GitHub Actions workflow file or composite action file"
case pkg.WordpressPluginPkg:
answer = "acquired package info from found wordpress plugin PHP source files"
default:
answer = "acquired package info from the following paths"
}
@@ -263,6 +263,14 @@ func Test_SourceInfo(t *testing.T) {
"from GitHub Actions workflow file or composite action file",
},
},
{
input: pkg.Package{
Type: pkg.WordpressPluginPkg,
},
expected: []string{
"acquired package info from found wordpress plugin PHP source files",
},
},
}
var pkgTypes []pkg.Type
for _, test := range tests {
@@ -12,7 +12,7 @@ import (
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/directorysource"
)
func DirectoryInput(t testing.TB, dir string) sbom.SBOM {
@@ -22,8 +22,8 @@ func DirectoryInput(t testing.TB, dir string) sbom.SBOM {
require.NoError(t, os.MkdirAll(path, 0755))
src, err := source.NewFromDirectory(
source.DirectoryConfig{
src, err := directorysource.New(
directorysource.Config{
Path: path,
Base: dir,
},
@@ -63,8 +63,8 @@ func DirectoryInputWithAuthorField(t testing.TB) sbom.SBOM {
require.NoError(t, os.MkdirAll(path, 0755))
src, err := source.NewFromDirectory(
source.DirectoryConfig{
src, err := directorysource.New(
directorysource.Config{
Path: path,
Base: dir,
},
+4 -4
View File
@@ -5,7 +5,6 @@ import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/stereoscope/pkg/filetree"
@@ -16,7 +15,7 @@ import (
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/stereoscopesource"
)
func ImageInput(t testing.TB, testImage string, options ...ImageOption) sbom.SBOM {
@@ -42,8 +41,9 @@ func ImageInput(t testing.TB, testImage string, options ...ImageOption) sbom.SBO
// this is a hard coded value that is not given by the fixture helper and must be provided manually
img.Metadata.ManifestDigest = "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
src, err := source.NewFromStereoscopeImageObject(img, "user-image-input", nil)
assert.NoError(t, err)
src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
Reference: "user-image-input",
})
return sbom.SBOM{
Artifacts: sbom.Artifacts{
+1 -1
View File
@@ -72,7 +72,7 @@ func TestSPDXJSONSPDXIDs(t *testing.T) {
Relationships: nil,
Source: source.Description{
Name: "foobar/baz", // in this case, foobar is used as the spdx document name
Metadata: source.DirectorySourceMetadata{},
Metadata: source.DirectoryMetadata{},
},
Descriptor: sbom.Descriptor{
Name: "syft",
+1 -1
View File
@@ -263,7 +263,7 @@ func Test_encodeDecodeFileMetadata(t *testing.T) {
ID: "some-id",
Name: "some-name",
Version: "some-version",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "/some-file-source-path",
Digests: []file.Digest{
{
+2 -2
View File
@@ -260,7 +260,7 @@ func TestEncodeFullJSONDocument(t *testing.T) {
},
Source: source.Description{
ID: "c2b46b4eb06296933b7cf0722683964e9ecbd93265b9ef6ae9642e3952afbba0",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "user-image-input",
ID: "sha256:c2b46b4eb06296933b7cf0722683964e9ecbd93265b9ef6ae9642e3952afbba0",
ManifestDigest: "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368",
@@ -269,7 +269,7 @@ func TestEncodeFullJSONDocument(t *testing.T) {
"stereoscope-fixture-image-simple:85066c51088bdd274f7a89e99e00490f666c49e72ffc955707cd6e18f0e22c5b",
},
Size: 38,
Layers: []source.StereoscopeLayerMetadata{
Layers: []source.LayerMetadata{
{
MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
Digest: "sha256:3de16c5b8659a2e8d888b8ded8427be7a5686a3c8c4e4dd30de20f362827285b",
+3 -3
View File
@@ -89,7 +89,7 @@ func extractPreSchemaV9Metadata(t string, target []byte) (interface{}, error) {
cleanTarget = string(target)
}
return source.DirectorySourceMetadata{
return source.DirectoryMetadata{
Path: cleanTarget,
}, nil
@@ -99,12 +99,12 @@ func extractPreSchemaV9Metadata(t string, target []byte) (interface{}, error) {
cleanTarget = string(target)
}
return source.FileSourceMetadata{
return source.FileMetadata{
Path: cleanTarget,
}, nil
case "image":
var payload source.StereoscopeImageSourceMetadata
var payload source.ImageMetadata
if err := json.Unmarshal(target, &payload); err != nil {
return nil, err
}
+9 -9
View File
@@ -32,7 +32,7 @@ func TestSource_UnmarshalJSON(t *testing.T) {
expected: &Source{
ID: "foobar",
Type: "directory",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "/var/lib/foo",
//Base: "/nope", // note: should be ignored entirely
},
@@ -67,14 +67,14 @@ func TestSource_UnmarshalJSON(t *testing.T) {
expected: &Source{
ID: "foobar",
Type: "image",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "alpine:3.10",
ID: "sha256:e7b300aee9f9bf3433d32bc9305bfdd22183beb59d933b48d77ab56ba53a197a",
ManifestDigest: "sha256:e515aad2ed234a5072c4d2ef86a1cb77d5bfe4b11aa865d9214875734c4eeb3c",
MediaType: "application/vnd.docker.distribution.manifest.v2+json",
Tags: []string{},
Size: 5576169,
Layers: []source.StereoscopeLayerMetadata{
Layers: []source.LayerMetadata{
{
MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
Digest: "sha256:9fb3aa2f8b8023a4bebbf92aa567caf88e38e969ada9f0ac12643b2847391635",
@@ -124,7 +124,7 @@ func TestSource_UnmarshalJSON(t *testing.T) {
expected: &Source{
ID: "foobar",
Type: "file",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "/var/lib/foo/go.mod",
Digests: []file.Digest{
{
@@ -188,7 +188,7 @@ func TestSource_UnmarshalJSON_PreSchemaV9(t *testing.T) {
expectedSource: &Source{
ID: "foobar",
Type: "directory",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "/var/lib/foo",
},
},
@@ -204,7 +204,7 @@ func TestSource_UnmarshalJSON_PreSchemaV9(t *testing.T) {
expectedSource: &Source{
ID: "foobar",
Type: "directory",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "/var/lib/foo",
},
},
@@ -239,14 +239,14 @@ func TestSource_UnmarshalJSON_PreSchemaV9(t *testing.T) {
expectedSource: &Source{
ID: "foobar",
Type: "image",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "alpine:3.10",
ID: "sha256:e7b300aee9f9bf3433d32bc9305bfdd22183beb59d933b48d77ab56ba53a197a",
ManifestDigest: "sha256:e515aad2ed234a5072c4d2ef86a1cb77d5bfe4b11aa865d9214875734c4eeb3c",
MediaType: "application/vnd.docker.distribution.manifest.v2+json",
Tags: []string{},
Size: 5576169,
Layers: []source.StereoscopeLayerMetadata{
Layers: []source.LayerMetadata{
{
MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
Digest: "sha256:9fb3aa2f8b8023a4bebbf92aa567caf88e38e969ada9f0ac12643b2847391635",
@@ -288,7 +288,7 @@ func TestSource_UnmarshalJSON_PreSchemaV9(t *testing.T) {
expectedSource: &Source{
ID: "foobar",
Type: "file",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "/var/lib/foo/go.mod",
},
},
+119
View File
@@ -0,0 +1,119 @@
package syftjson
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"github.com/iancoleman/strcase"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/internal/packagemetadata"
)
type schema struct {
Schema string `json:"$schema"`
ID string `json:"$id"`
Ref string `json:"$ref"`
Defs map[string]properties `json:"$defs"`
}
type properties struct {
Properties map[string]any `json:"properties"`
Type string `json:"type"`
Required []string `json:"required"`
}
func (p properties) fields() []string {
var result []string
for k := range p.Properties {
result = append(result, k)
}
return result
}
func Test_JSONSchemaConventions(t *testing.T) {
// read schema/json/schema-latest.json
// look at all attributes and ensure that all fields are camelCase
// we want to strictly follow https://google.github.io/styleguide/javaguide.html#s5.3-camel-case
//
// > Convert the phrase to plain ASCII and remove any apostrophes. For example, "Müller's algorithm" might become "Muellers algorithm".
// > Divide this result into words, splitting on spaces and any remaining punctuation (typically hyphens).
// > Recommended: if any word already has a conventional camel-case appearance in common usage, split this into its constituent parts (e.g., "AdWords" becomes "ad words"). Note that a word such as "iOS" is not really in camel case per se; it defies any convention, so this recommendation does not apply.
// > Now lowercase everything (including acronyms), then uppercase only the first character of:
// > ... each word, to yield upper camel case, or
// > ... each word except the first, to yield lower camel case
// > Finally, join all the words into a single identifier.
//
// This means that acronyms should be treated as words (e.g. "HttpServer" not "HTTPServer")
root, err := packagemetadata.RepoRoot()
require.NoError(t, err)
contents, err := os.ReadFile(filepath.Join(root, "schema", "json", "schema-latest.json"))
require.NoError(t, err)
var s schema
require.NoError(t, json.Unmarshal(contents, &s))
require.NotEmpty(t, s.Defs)
for name, def := range s.Defs {
checkAndConvertFields(t, name, def.fields())
}
}
func checkAndConvertFields(t *testing.T, path string, properties []string) {
for _, fieldName := range properties {
if pass, exp := isFollowingConvention(path, fieldName); !pass {
t.Logf("%s: has non camel case field: %q (expected %q)", path, fieldName, exp)
}
}
}
func isFollowingConvention(path, fieldName string) (bool, string) {
exp := strcase.ToLowerCamel(fieldName)
result := exp == fieldName
exception := func(exceptions ...string) (bool, string) {
for _, e := range exceptions {
if e == fieldName {
return true, fieldName
}
}
return result, exp
}
// add exceptions as needed... these are grandfathered in and will be addressed in a future breaking schema change
// ideally in the future there will be no exceptions to the camel case convention for fields
switch path {
case "Coordinates", "Location":
return exception("layerID")
case "MicrosoftKbPatch":
return exception("product_id")
case "HaskellHackageStackLockEntry":
return exception("snapshotURL")
case "LinuxRelease":
return exception("imageID", "supportURL", "privacyPolicyURL", "versionID", "variantID", "homeURL", "buildID", "bugReportURL")
case "CConanLockV2Entry":
return exception("packageID")
case "CConanInfoEntry":
return exception("package_id")
case "PhpComposerInstalledEntry", "PhpComposerLockEntry":
return exception("notification-url", "require-dev")
case "LinuxKernelArchive":
return exception("rwRootFS")
case "CConanLockEntry":
return exception("build_requires", "py_requires", "package_id")
case "FileMetadataEntry":
return exception("userID", "groupID")
case "DartPubspecLockEntry":
return exception("hosted_url", "vcs_url")
case "ELFSecurityFeatures":
return exception("relRO")
}
return result, exp
}
+1 -1
View File
@@ -303,7 +303,7 @@ func toSourceModel(src source.Description) model.Source {
Metadata: src.Metadata,
}
if metadata, ok := src.Metadata.(source.StereoscopeImageSourceMetadata); ok {
if metadata, ok := src.Metadata.(source.ImageMetadata); ok {
// ensure that empty collections are not shown as null
if metadata.RepoDigests == nil {
metadata.RepoDigests = []string{}
+13 -13
View File
@@ -26,7 +26,7 @@ func Test_toSourceModel_IgnoreBase(t *testing.T) {
name: "directory",
src: source.Description{
ID: "test-id",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path",
Base: "some/base",
},
@@ -59,7 +59,7 @@ func Test_toSourceModel(t *testing.T) {
ID: "test-id",
Name: "some-name",
Version: "some-version",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path",
Base: "some/base",
},
@@ -69,7 +69,7 @@ func Test_toSourceModel(t *testing.T) {
Name: "some-name",
Version: "some-version",
Type: "directory",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path",
Base: "some/base",
},
@@ -81,7 +81,7 @@ func Test_toSourceModel(t *testing.T) {
ID: "test-id",
Name: "some-name",
Version: "some-version",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "some/path",
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
MIMEType: "text/plain",
@@ -92,7 +92,7 @@ func Test_toSourceModel(t *testing.T) {
Name: "some-name",
Version: "some-version",
Type: "file",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "some/path",
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
MIMEType: "text/plain",
@@ -105,7 +105,7 @@ func Test_toSourceModel(t *testing.T) {
ID: "test-id",
Name: "some-name",
Version: "some-version",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "user-input",
ID: "id...",
ManifestDigest: "digest...",
@@ -117,7 +117,7 @@ func Test_toSourceModel(t *testing.T) {
Name: "some-name",
Version: "some-version",
Type: "image",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "user-input",
ID: "id...",
ManifestDigest: "digest...",
@@ -133,7 +133,7 @@ func Test_toSourceModel(t *testing.T) {
name: "directory - no name/version",
src: source.Description{
ID: "test-id",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path",
Base: "some/base",
},
@@ -141,7 +141,7 @@ func Test_toSourceModel(t *testing.T) {
expected: model.Source{
ID: "test-id",
Type: "directory",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path",
Base: "some/base",
},
@@ -151,7 +151,7 @@ func Test_toSourceModel(t *testing.T) {
name: "file - no name/version",
src: source.Description{
ID: "test-id",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "some/path",
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
MIMEType: "text/plain",
@@ -160,7 +160,7 @@ func Test_toSourceModel(t *testing.T) {
expected: model.Source{
ID: "test-id",
Type: "file",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "some/path",
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
MIMEType: "text/plain",
@@ -171,7 +171,7 @@ func Test_toSourceModel(t *testing.T) {
name: "image - no name/version",
src: source.Description{
ID: "test-id",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "user-input",
ID: "id...",
ManifestDigest: "digest...",
@@ -181,7 +181,7 @@ func Test_toSourceModel(t *testing.T) {
expected: model.Source{
ID: "test-id",
Type: "image",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "user-input",
ID: "id...",
ManifestDigest: "digest...",
+13 -13
View File
@@ -35,7 +35,7 @@ func Test_toSyftSourceData(t *testing.T) {
Name: "some-name",
Version: "some-version",
Type: "directory",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path",
Base: "some/base",
},
@@ -44,7 +44,7 @@ func Test_toSyftSourceData(t *testing.T) {
ID: "the-id",
Name: "some-name",
Version: "some-version",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path",
Base: "some/base",
},
@@ -57,7 +57,7 @@ func Test_toSyftSourceData(t *testing.T) {
Name: "some-name",
Version: "some-version",
Type: "file",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "some/path",
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
MIMEType: "text/plain",
@@ -67,7 +67,7 @@ func Test_toSyftSourceData(t *testing.T) {
ID: "the-id",
Name: "some-name",
Version: "some-version",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "some/path",
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
MIMEType: "text/plain",
@@ -81,7 +81,7 @@ func Test_toSyftSourceData(t *testing.T) {
Name: "some-name",
Version: "some-version",
Type: "image",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "user-input",
ID: "id...",
ManifestDigest: "digest...",
@@ -92,7 +92,7 @@ func Test_toSyftSourceData(t *testing.T) {
ID: "the-id",
Name: "some-name",
Version: "some-version",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "user-input",
ID: "id...",
ManifestDigest: "digest...",
@@ -107,14 +107,14 @@ func Test_toSyftSourceData(t *testing.T) {
src: model.Source{
ID: "the-id",
Type: "directory",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path",
Base: "some/base",
},
},
expected: &source.Description{
ID: "the-id",
Metadata: source.DirectorySourceMetadata{
Metadata: source.DirectoryMetadata{
Path: "some/path",
Base: "some/base",
},
@@ -125,7 +125,7 @@ func Test_toSyftSourceData(t *testing.T) {
src: model.Source{
ID: "the-id",
Type: "file",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "some/path",
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
MIMEType: "text/plain",
@@ -133,7 +133,7 @@ func Test_toSyftSourceData(t *testing.T) {
},
expected: &source.Description{
ID: "the-id",
Metadata: source.FileSourceMetadata{
Metadata: source.FileMetadata{
Path: "some/path",
Digests: []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
MIMEType: "text/plain",
@@ -145,7 +145,7 @@ func Test_toSyftSourceData(t *testing.T) {
src: model.Source{
ID: "the-id",
Type: "image",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "user-input",
ID: "id...",
ManifestDigest: "digest...",
@@ -154,7 +154,7 @@ func Test_toSyftSourceData(t *testing.T) {
},
expected: &source.Description{
ID: "the-id",
Metadata: source.StereoscopeImageSourceMetadata{
Metadata: source.ImageMetadata{
UserInput: "user-input",
ID: "id...",
ManifestDigest: "digest...",
@@ -178,7 +178,7 @@ func Test_idsHaveChanged(t *testing.T) {
s := toSyftModel(model.Document{
Source: model.Source{
Type: "file",
Metadata: source.FileSourceMetadata{Path: "some/path"},
Metadata: source.FileMetadata{Path: "some/path"},
},
Artifacts: []model.Package{
{
+27 -5
View File
@@ -6,6 +6,7 @@ import (
"sort"
"strings"
"github.com/charmbracelet/lipgloss"
"github.com/olekukonko/tablewriter"
"github.com/anchore/syft/syft/sbom"
@@ -61,7 +62,9 @@ func (e encoder) Encode(writer io.Writer, s sbom.SBOM) error {
}
return false
})
rows = removeDuplicateRows(rows)
columns = append(columns, "") // add a column for duplicate annotations
rows = markDuplicateRows(rows)
table := tablewriter.NewWriter(writer)
@@ -84,19 +87,38 @@ func (e encoder) Encode(writer io.Writer, s sbom.SBOM) error {
return nil
}
func removeDuplicateRows(items [][]string) [][]string {
seen := map[string][]string{}
func markDuplicateRows(items [][]string) [][]string {
seen := map[string]int{}
var result [][]string
for _, v := range items {
key := strings.Join(v, "|")
if seen[key] != nil {
if _, ok := seen[key]; ok {
// dup!
seen[key]++
continue
}
seen[key] = v
seen[key] = 1
result = append(result, v)
}
style := lipgloss.NewStyle().Foreground(lipgloss.Color("#777777"))
for i, v := range result {
key := strings.Join(v, "|")
// var name string
var annotation string
switch seen[key] {
case 0, 1:
case 2:
annotation = "(+1 duplicate)"
default:
annotation = fmt.Sprintf("(+%d duplicates)", seen[key]-1)
}
annotation = style.Render(annotation)
result[i] = append(v, annotation)
}
return result
}
+6 -6
View File
@@ -23,7 +23,7 @@ func TestTableEncoder(t *testing.T) {
)
}
func TestRemoveDuplicateRows(t *testing.T) {
func Test_markDuplicateRows(t *testing.T) {
data := [][]string{
{"1", "2", "3"},
{"a", "b", "c"},
@@ -35,13 +35,13 @@ func TestRemoveDuplicateRows(t *testing.T) {
}
expected := [][]string{
{"1", "2", "3"},
{"a", "b", "c"},
{"4", "5", "6"},
{"1", "2", "1"},
{"1", "2", "3", "(+2 duplicates)"},
{"a", "b", "c", "(+1 duplicate)"},
{"4", "5", "6", ""},
{"1", "2", "1", ""},
}
actual := removeDuplicateRows(data)
actual := markDuplicateRows(data)
if diffs := deep.Equal(expected, actual); len(diffs) > 0 {
t.Errorf("found diffs!")
@@ -1,3 +1,3 @@
NAME VERSION TYPE
package-1 1.0.1 python
package-2 2.0.1 deb
NAME VERSION TYPE
package-1 1.0.1 python
package-2 2.0.1 deb
+3 -3
View File
@@ -38,11 +38,11 @@ func (e encoder) Encode(writer io.Writer, s sbom.SBOM) error {
w.Init(writer, 0, 8, 0, '\t', tabwriter.AlignRight)
switch metadata := s.Source.Metadata.(type) {
case source.DirectorySourceMetadata:
case source.DirectoryMetadata:
fmt.Fprintf(w, "[Path: %s]\n", metadata.Path)
case source.FileSourceMetadata:
case source.FileMetadata:
fmt.Fprintf(w, "[Path: %s]\n", metadata.Path)
case source.StereoscopeImageSourceMetadata:
case source.ImageMetadata:
fmt.Fprintln(w, "[Image]")
for idx, l := range metadata.Layers {
+101
View File
@@ -0,0 +1,101 @@
package syft
import (
"context"
"errors"
"fmt"
"os"
"github.com/anchore/syft/syft/source"
)
// GetSource uses all of Syft's known source providers to attempt to resolve the user input to a usable source.Source
func GetSource(ctx context.Context, userInput string, cfg *GetSourceConfig) (source.Source, error) {
if cfg == nil {
cfg = DefaultGetSourceConfig()
}
providers, err := cfg.getProviders(userInput)
if err != nil {
return nil, err
}
var errs []error
var fileNotfound error
// call each source provider until we find a valid source
for _, p := range providers {
src, err := p.Provide(ctx)
if err != nil {
err = eachError(err, func(err error) error {
if errors.Is(err, os.ErrNotExist) {
fileNotfound = err
return nil
}
return err
})
if err != nil {
errs = append(errs, err)
}
}
if src != nil {
// if we have a non-image type and platform is specified, it's an error
if cfg.SourceProviderConfig.Platform != nil {
meta := src.Describe().Metadata
switch meta.(type) {
case *source.ImageMetadata, source.ImageMetadata:
default:
return src, fmt.Errorf("platform specified with non-image source")
}
}
return src, nil
}
}
if fileNotfound != nil {
errs = append([]error{fileNotfound}, errs...)
}
return nil, sourceError(userInput, errs...)
}
func sourceError(userInput string, errs ...error) error {
switch len(errs) {
case 0:
return nil
case 1:
return fmt.Errorf("an error occurred attempting to resolve '%s': %w", userInput, errs[0])
}
errorTexts := ""
for _, e := range errs {
errorTexts += fmt.Sprintf("\n - %s", e)
}
return fmt.Errorf("errors occurred attempting to resolve '%s':%s", userInput, errorTexts)
}
func eachError(err error, fn func(error) error) error {
out := fn(err)
// unwrap singly wrapped errors
if e, ok := err.(interface {
Unwrap() error
}); ok {
wrapped := e.Unwrap()
got := eachError(wrapped, fn)
// return the outer error if received the same wrapped error
if errors.Is(got, wrapped) {
return err
}
return got
}
// unwrap errors from errors.Join
if errs, ok := err.(interface {
Unwrap() []error
}); ok {
for _, e := range errs.Unwrap() {
e = eachError(e, fn)
if e != nil {
out = errors.Join(out, e)
}
}
}
return out
}
+91
View File
@@ -0,0 +1,91 @@
package syft
import (
"crypto"
"fmt"
"github.com/anchore/go-collections"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/sourceproviders"
)
type GetSourceConfig struct {
// SourceProviderConfig may optionally be provided to be used when constructing the default set of source providers, unused if All specified
SourceProviderConfig *sourceproviders.Config
// Sources is an explicit list of source names to use, in order, to attempt to locate a source
Sources []string
// DefaultImagePullSource will cause a particular image pull source to be used as the first pull source, followed by other pull sources
DefaultImagePullSource string
}
func (c *GetSourceConfig) WithAlias(alias source.Alias) *GetSourceConfig {
c.SourceProviderConfig = c.SourceProviderConfig.WithAlias(alias)
return c
}
func (c *GetSourceConfig) WithRegistryOptions(registryOptions *image.RegistryOptions) *GetSourceConfig {
c.SourceProviderConfig = c.SourceProviderConfig.WithRegistryOptions(registryOptions)
return c
}
func (c *GetSourceConfig) WithPlatform(platform *image.Platform) *GetSourceConfig {
c.SourceProviderConfig = c.SourceProviderConfig.WithPlatform(platform)
return c
}
func (c *GetSourceConfig) WithExcludeConfig(excludeConfig source.ExcludeConfig) *GetSourceConfig {
c.SourceProviderConfig = c.SourceProviderConfig.WithExcludeConfig(excludeConfig)
return c
}
func (c *GetSourceConfig) WithDigestAlgorithms(algorithms ...crypto.Hash) *GetSourceConfig {
c.SourceProviderConfig = c.SourceProviderConfig.WithDigestAlgorithms(algorithms...)
return c
}
func (c *GetSourceConfig) WithBasePath(basePath string) *GetSourceConfig {
c.SourceProviderConfig = c.SourceProviderConfig.WithBasePath(basePath)
return c
}
func (c *GetSourceConfig) WithSources(sources ...string) *GetSourceConfig {
c.Sources = sources
return c
}
func (c *GetSourceConfig) WithDefaultImagePullSource(defaultImagePullSource string) *GetSourceConfig {
c.DefaultImagePullSource = defaultImagePullSource
return c
}
func (c *GetSourceConfig) getProviders(userInput string) ([]source.Provider, error) {
providers := collections.TaggedValueSet[source.Provider]{}.Join(sourceproviders.All(userInput, c.SourceProviderConfig)...)
// if the "default image pull source" is set, we move this as the first pull source
if c.DefaultImagePullSource != "" {
base := providers.Remove(sourceproviders.PullTag)
pull := providers.Select(sourceproviders.PullTag)
def := pull.Select(c.DefaultImagePullSource)
if len(def) == 0 {
return nil, fmt.Errorf("invalid DefaultImagePullSource: %s; available values are: %v", c.DefaultImagePullSource, pull.Tags())
}
providers = base.Join(def...).Join(pull...)
}
// narrow the sources to those explicitly requested generally by a user
if len(c.Sources) > 0 {
// select the explicitly provided sources, in order
providers = providers.Select(c.Sources...)
}
return providers.Values(), nil
}
func DefaultGetSourceConfig() *GetSourceConfig {
return &GetSourceConfig{
SourceProviderConfig: sourceproviders.DefaultConfig(),
}
}
-6
View File
@@ -14,12 +14,6 @@ import (
"github.com/anchore/syft/syft/internal/windows"
)
var unixSystemRuntimePrefixes = []string{
"/proc",
"/dev",
"/sys",
}
var ErrSkipPath = errors.New("skip path")
var _ file.Resolver = (*Directory)(nil)
+77 -19
View File
@@ -9,6 +9,7 @@ import (
"path/filepath"
"strings"
"github.com/moby/sys/mountinfo"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
@@ -21,7 +22,7 @@ import (
"github.com/anchore/syft/syft/internal/windows"
)
type PathIndexVisitor func(string, os.FileInfo, error) error
type PathIndexVisitor func(string, string, os.FileInfo, error) error
type directoryIndexer struct {
path string
@@ -34,12 +35,18 @@ type directoryIndexer struct {
func newDirectoryIndexer(path, base string, visitors ...PathIndexVisitor) *directoryIndexer {
i := &directoryIndexer{
path: path,
base: base,
tree: filetree.New(),
index: filetree.NewIndex(),
pathIndexVisitors: append([]PathIndexVisitor{requireFileInfo, disallowByFileType, disallowUnixSystemRuntimePath}, visitors...),
errPaths: make(map[string]error),
path: path,
base: base,
tree: filetree.New(),
index: filetree.NewIndex(),
pathIndexVisitors: append(
[]PathIndexVisitor{
requireFileInfo,
disallowByFileType,
newUnixSystemMountFinder().disallowUnixSystemRuntimePath},
visitors...,
),
errPaths: make(map[string]error),
}
// these additional stateful visitors should be the first thing considered when walking / indexing
@@ -176,6 +183,13 @@ func isRealPath(root string) (bool, error) {
func (r *directoryIndexer) indexBranch(root string, stager *progress.Stage) ([]string, error) {
rootRealPath, err := filepath.EvalSymlinks(root)
if err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) {
// we can't index the path, but we shouldn't consider this to be fatal
// TODO: known-unknowns
log.WithFields("root", root, "error", err).Trace("unable to evaluate symlink while indexing branch")
return nil, nil
}
return nil, err
}
@@ -239,14 +253,14 @@ func allContainedPaths(p string) []string {
return all
}
func (r *directoryIndexer) indexPath(path string, info os.FileInfo, err error) (string, error) {
func (r *directoryIndexer) indexPath(givenPath string, info os.FileInfo, err error) (string, error) {
// ignore any path which a filter function returns true
for _, filterFn := range r.pathIndexVisitors {
if filterFn == nil {
continue
}
if filterErr := filterFn(path, info, err); filterErr != nil {
if filterErr := filterFn(r.base, givenPath, info, err); filterErr != nil {
if errors.Is(filterErr, fs.SkipDir) {
// signal to walk() to skip this directory entirely (even if we're processing a file)
return "", filterErr
@@ -258,24 +272,24 @@ func (r *directoryIndexer) indexPath(path string, info os.FileInfo, err error) (
if info == nil {
// walk may not be able to provide a FileInfo object, don't allow for this to stop indexing; keep track of the paths and continue.
r.errPaths[path] = fmt.Errorf("no file info observable at path=%q", path)
r.errPaths[givenPath] = fmt.Errorf("no file info observable at path=%q", givenPath)
return "", nil
}
// here we check to see if we need to normalize paths to posix on the way in coming from windows
if windows.HostRunningOnWindows() {
path = windows.ToPosix(path)
givenPath = windows.ToPosix(givenPath)
}
newRoot, err := r.addPathToIndex(path, info)
if r.isFileAccessErr(path, err) {
newRoot, err := r.addPathToIndex(givenPath, info)
if r.isFileAccessErr(givenPath, err) {
return "", nil
}
return newRoot, nil
}
func (r *directoryIndexer) disallowFileAccessErr(path string, _ os.FileInfo, err error) error {
func (r *directoryIndexer) disallowFileAccessErr(_, path string, _ os.FileInfo, err error) error {
if r.isFileAccessErr(path, err) {
return ErrSkipPath
}
@@ -422,7 +436,7 @@ func (r directoryIndexer) hasBeenIndexed(p string) (bool, *file.Metadata) {
return true, &entry.Metadata
}
func (r *directoryIndexer) disallowRevisitingVisitor(path string, _ os.FileInfo, _ error) error {
func (r *directoryIndexer) disallowRevisitingVisitor(_, path string, _ os.FileInfo, _ error) error {
// this prevents visiting:
// - link destinations twice, once for the real file and another through the virtual path
// - infinite link cycles
@@ -436,14 +450,58 @@ func (r *directoryIndexer) disallowRevisitingVisitor(path string, _ os.FileInfo,
return nil
}
func disallowUnixSystemRuntimePath(path string, _ os.FileInfo, _ error) error {
if internal.HasAnyOfPrefixes(path, unixSystemRuntimePrefixes...) {
type unixSystemMountFinder struct {
disallowedMountPaths []string
}
func newUnixSystemMountFinder() unixSystemMountFinder {
infos, err := mountinfo.GetMounts(nil)
if err != nil {
log.WithFields("error", err).Warnf("unable to get system mounts")
return unixSystemMountFinder{}
}
return unixSystemMountFinder{
disallowedMountPaths: keepUnixSystemMountPaths(infos),
}
}
func keepUnixSystemMountPaths(infos []*mountinfo.Info) []string {
var mountPaths []string
for _, info := range infos {
if info == nil {
continue
}
// we're only interested in ignoring the logical filesystems typically found at these mount points:
// - /proc
// - procfs
// - proc
// - /sys
// - sysfs
// - /dev
// - devfs - BSD/darwin flavored systems and old linux systems
// - devtmpfs - driver core maintained /dev tmpfs
// - udev - userspace implementation that replaced devfs
// - tmpfs - used for /dev in special instances (within a container)
switch info.FSType {
case "proc", "procfs", "sysfs", "devfs", "devtmpfs", "udev", "tmpfs":
log.WithFields("mountpoint", info.Mountpoint).Debug("ignoring system mountpoint")
mountPaths = append(mountPaths, info.Mountpoint)
}
}
return mountPaths
}
func (f unixSystemMountFinder) disallowUnixSystemRuntimePath(_, path string, _ os.FileInfo, _ error) error {
if internal.HasAnyOfPrefixes(path, f.disallowedMountPaths...) {
return fs.SkipDir
}
return nil
}
func disallowByFileType(_ string, info os.FileInfo, _ error) error {
func disallowByFileType(_, _ string, info os.FileInfo, _ error) error {
if info == nil {
// we can't filter out by filetype for non-existent files
return nil
@@ -458,7 +516,7 @@ func disallowByFileType(_ string, info os.FileInfo, _ error) error {
return nil
}
func requireFileInfo(_ string, info os.FileInfo, _ error) error {
func requireFileInfo(_, _ string, info os.FileInfo, _ error) error {
if info == nil {
return ErrSkipPath
}
@@ -4,11 +4,13 @@ import (
"io/fs"
"os"
"path"
"path/filepath"
"sort"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/moby/sys/mountinfo"
"github.com/scylladb/go-set/strset"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -135,7 +137,7 @@ func TestDirectoryIndexer_handleFileAccessErr(t *testing.T) {
}
func TestDirectoryIndexer_IncludeRootPathInIndex(t *testing.T) {
filterFn := func(path string, _ os.FileInfo, _ error) error {
filterFn := func(_, path string, _ os.FileInfo, _ error) error {
if path != "/" {
return fs.SkipDir
}
@@ -222,9 +224,21 @@ func TestDirectoryIndexer_index(t *testing.T) {
}
}
func TestDirectoryIndexer_index_survive_badSymlink(t *testing.T) {
// test-fixtures/bad-symlinks
// ├── root
// │ ├── place
// │ │ └── fd -> ../somewhere/self/fd
// │ └── somewhere
// ...
indexer := newDirectoryIndexer("test-fixtures/bad-symlinks/root/place/fd", "test-fixtures/bad-symlinks/root/place/fd")
_, _, err := indexer.build()
require.NoError(t, err)
}
func TestDirectoryIndexer_SkipsAlreadyVisitedLinkDestinations(t *testing.T) {
var observedPaths []string
pathObserver := func(p string, _ os.FileInfo, _ error) error {
pathObserver := func(_, p string, _ os.FileInfo, _ error) error {
fields := strings.Split(p, "test-fixtures/symlinks-prune-indexing")
if len(fields) < 2 {
return nil
@@ -383,3 +397,210 @@ func Test_allContainedPaths(t *testing.T) {
})
}
}
func Test_relativePath(t *testing.T) {
tests := []struct {
name string
basePath string
givenPath string
want string
}{
{
name: "root: same relative path",
basePath: "a/b/c",
givenPath: "a/b/c",
want: "/",
},
{
name: "root: same absolute path",
basePath: "/a/b/c",
givenPath: "/a/b/c",
want: "/",
},
{
name: "contained path: relative",
basePath: "a/b/c",
givenPath: "a/b/c/dev",
want: "/dev",
},
{
name: "contained path: absolute",
basePath: "/a/b/c",
givenPath: "/a/b/c/dev",
want: "/dev",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, relativePath(tt.basePath, tt.givenPath))
})
}
}
func relativePath(basePath, givenPath string) string {
var relPath string
var relErr error
if basePath != "" {
relPath, relErr = filepath.Rel(basePath, givenPath)
cleanPath := filepath.Clean(relPath)
if relErr == nil {
if cleanPath == "." {
relPath = string(filepath.Separator)
} else {
relPath = cleanPath
}
}
if !filepath.IsAbs(relPath) {
relPath = string(filepath.Separator) + relPath
}
}
if relErr != nil || basePath == "" {
relPath = givenPath
}
return relPath
}
func Test_disallowUnixSystemRuntimePath(t *testing.T) {
unixSubject := unixSystemMountFinder{
// mock out detecting the mount points
disallowedMountPaths: []string{"/proc", "/sys", "/dev"},
}
tests := []struct {
name string
path string
base string
expected error
}{
{
name: "relative path to proc is allowed",
path: "proc/place",
},
{
name: "relative path within proc is not allowed",
path: "/proc/place",
expected: fs.SkipDir,
},
{
name: "path exactly to proc is not allowed",
path: "/proc",
expected: fs.SkipDir,
},
{
name: "similar to proc",
path: "/pro/c",
},
{
name: "similar to proc",
path: "/pro",
},
{
name: "dev is not allowed",
path: "/dev",
expected: fs.SkipDir,
},
{
name: "sys is not allowed",
path: "/sys",
expected: fs.SkipDir,
},
{
name: "unrelated allowed path",
path: "/something/sys",
},
{
name: "do not consider base when matching paths (non-matching)",
base: "/a/b/c",
path: "/a/b/c/dev",
},
{
name: "do not consider base when matching paths (matching)",
base: "/a/b/c",
path: "/dev",
expected: fs.SkipDir,
},
}
for _, test := range tests {
t.Run(test.path, func(t *testing.T) {
assert.Equal(t, test.expected, unixSubject.disallowUnixSystemRuntimePath(test.base, test.path, nil, nil))
})
}
}
func Test_keepUnixSystemMountPaths(t *testing.T) {
tests := []struct {
name string
infos []*mountinfo.Info
want []string
}{
{
name: "all valid filesystems",
infos: []*mountinfo.Info{
{
Mountpoint: "/etc/hostname",
FSType: "/dev/vda1",
},
{
Mountpoint: "/sys/fs/cgroup",
FSType: "cgroup",
},
{
Mountpoint: "/",
FSType: "overlay",
},
},
want: nil,
},
{
name: "no valid filesystems",
infos: []*mountinfo.Info{
{
Mountpoint: "/proc",
FSType: "proc",
},
{
Mountpoint: "/proc-2",
FSType: "procfs",
},
{
Mountpoint: "/sys",
FSType: "sysfs",
},
{
Mountpoint: "/dev",
FSType: "devfs",
},
{
Mountpoint: "/dev-u",
FSType: "udev",
},
{
Mountpoint: "/dev-tmp",
FSType: "devtmpfs",
},
{
Mountpoint: "/run",
FSType: "tmpfs",
},
},
want: []string{
"/proc",
"/proc-2",
"/sys",
"/dev",
"/dev-u",
"/dev-tmp",
"/run",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, keepUnixSystemMountPaths(tt.infos))
})
}
}
+2 -43
View File
@@ -918,7 +918,7 @@ func Test_isUnallowableFileType(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expected, disallowByFileType("dont/care", test.info, nil))
assert.Equal(t, test.expected, disallowByFileType("", "dont/care", test.info, nil))
})
}
}
@@ -999,7 +999,7 @@ func Test_IndexingNestedSymLinks(t *testing.T) {
}
func Test_IndexingNestedSymLinks_ignoredIndexes(t *testing.T) {
filterFn := func(path string, _ os.FileInfo, _ error) error {
filterFn := func(_, path string, _ os.FileInfo, _ error) error {
if strings.HasSuffix(path, string(filepath.Separator)+"readme") {
return ErrSkipPath
}
@@ -1108,47 +1108,6 @@ func Test_directoryResolver_FileContentsByLocation(t *testing.T) {
}
}
func Test_isUnixSystemRuntimePath(t *testing.T) {
tests := []struct {
path string
expected error
}{
{
path: "proc/place",
},
{
path: "/proc/place",
expected: fs.SkipDir,
},
{
path: "/proc",
expected: fs.SkipDir,
},
{
path: "/pro/c",
},
{
path: "/pro",
},
{
path: "/dev",
expected: fs.SkipDir,
},
{
path: "/sys",
expected: fs.SkipDir,
},
{
path: "/something/sys",
},
}
for _, test := range tests {
t.Run(test.path, func(t *testing.T) {
assert.Equal(t, test.expected, disallowUnixSystemRuntimePath(test.path, nil, nil))
})
}
}
func Test_SymlinkLoopWithGlobsShouldResolve(t *testing.T) {
test := func(t *testing.T) {
resolver, err := NewFromDirectory("./test-fixtures/symlinks-loop", "")
@@ -0,0 +1 @@
../somewhere/self/fd
@@ -232,7 +232,7 @@ func (u UnindexedDirectory) AllLocations(ctx context.Context) <-chan file.Locati
errWalkCanceled := fmt.Errorf("walk canceled")
go func() {
defer close(out)
err := afero.Walk(u.fs, u.absPath("."), func(p string, info fs.FileInfo, err error) error {
err := afero.Walk(u.fs, u.absPath("."), func(p string, _ fs.FileInfo, _ error) error {
p = strings.TrimPrefix(p, u.dir)
if p == "" {
return nil
@@ -46,6 +46,7 @@ func AllTypes() []any {
pkg.RustBinaryAuditEntry{},
pkg.RustCargoLockEntry{},
pkg.SwiftPackageManagerResolvedEntry{},
pkg.WordpressPluginEntry{},
pkg.YarnLockEntry{},
}
}
+1
View File
@@ -102,6 +102,7 @@ var jsonTypes = makeJSONTypes(
jsonNames(pkg.SwiftPackageManagerResolvedEntry{}, "swift-package-manager-lock-entry", "SwiftPackageManagerMetadata"),
jsonNames(pkg.RustCargoLockEntry{}, "rust-cargo-lock-entry", "RustCargoPackageMetadata"),
jsonNamesWithoutLookup(pkg.RustBinaryAuditEntry{}, "rust-cargo-audit-entry", "RustCargoPackageMetadata"), // the legacy value is split into two types, where the other is preferred
jsonNames(pkg.WordpressPluginEntry{}, "wordpress-plugin-entry", "WordpressMetadata"),
)
func expandLegacyNameVariants(names ...string) []string {
+1 -1
View File
@@ -6,5 +6,5 @@ import "github.com/anchore/syft/syft/source"
// AllTypes returns a list of all source metadata types that syft supports (that are represented in the source.Description.Metadata field).
func AllTypes() []any {
return []any{source.DirectorySourceMetadata{}, source.FileSourceMetadata{}, source.StereoscopeImageSourceMetadata{}}
return []any{source.DirectoryMetadata{}, source.FileMetadata{}, source.ImageMetadata{}}
}
+3 -3
View File
@@ -8,9 +8,9 @@ import (
)
var jsonNameFromType = map[reflect.Type][]string{
reflect.TypeOf(source.DirectorySourceMetadata{}): {"directory", "dir"},
reflect.TypeOf(source.FileSourceMetadata{}): {"file"},
reflect.TypeOf(source.StereoscopeImageSourceMetadata{}): {"image"},
reflect.TypeOf(source.DirectoryMetadata{}): {"directory", "dir"},
reflect.TypeOf(source.FileMetadata{}): {"file"},
reflect.TypeOf(source.ImageMetadata{}): {"image"},
}
func AllTypeNames() []string {
+26
View File
@@ -0,0 +1,26 @@
package testutil
import (
"os"
"testing"
"github.com/stretchr/testify/require"
)
func Chdir(t *testing.T, dir string) {
t.Helper()
wd, err := os.Getwd()
if err != nil {
t.Fatalf("unable to get working directory: %v", err)
}
err = os.Chdir(dir)
if err != nil {
t.Fatalf("unable to chdir to '%s': %v", dir, err)
}
t.Cleanup(func() {
require.NoError(t, os.Chdir(wd))
})
}
+2 -2
View File
@@ -9,7 +9,7 @@ import (
"github.com/anchore/syft/internal/log"
)
// unionReader is a single interface with all reading functions needed by multi-arch binary catalogers
// UnionReader is a single interface with all reading functions needed by multi-arch binary catalogers
// cataloger.
type UnionReader interface {
io.Reader
@@ -18,7 +18,7 @@ type UnionReader interface {
io.Closer
}
// getReaders extracts one or more io.ReaderAt objects representing binaries that can be processed (multiple binaries in the case for multi-architecture binaries).
// GetReaders extracts one or more io.ReaderAt objects representing binaries that can be processed (multiple binaries in the case for multi-architecture binaries).
func GetReaders(f UnionReader) ([]io.ReaderAt, error) {
if macho.IsUniversalMachoBinary(f) {
machoReaders, err := macho.ExtractReaders(f)
+4 -1
View File
@@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/directorysource"
)
func TestIdentifyRelease(t *testing.T) {
@@ -336,7 +337,9 @@ func TestIdentifyRelease(t *testing.T) {
for _, test := range tests {
t.Run(test.fixture, func(t *testing.T) {
s, err := source.NewFromDirectoryPath(test.fixture)
s, err := directorysource.New(directorysource.Config{
Path: test.fixture,
})
require.NoError(t, err)
resolver, err := s.FileResolver(source.SquashedScope)
+6 -6
View File
@@ -13,25 +13,25 @@ import (
"github.com/anchore/syft/syft/pkg"
)
const catalogerName = "binary-cataloger"
const catalogerName = "binary-classifier-cataloger"
type CatalogerConfig struct {
type ClassifierCatalogerConfig struct {
Classifiers []Classifier `yaml:"classifiers" json:"classifiers" mapstructure:"classifiers"`
}
func DefaultCatalogerConfig() CatalogerConfig {
return CatalogerConfig{
func DefaultClassifierCatalogerConfig() ClassifierCatalogerConfig {
return ClassifierCatalogerConfig{
Classifiers: DefaultClassifiers(),
}
}
func NewCataloger(cfg CatalogerConfig) pkg.Cataloger {
func NewClassifierCataloger(cfg ClassifierCatalogerConfig) pkg.Cataloger {
return &cataloger{
classifiers: cfg.Classifiers,
}
}
func (cfg CatalogerConfig) MarshalJSON() ([]byte, error) {
func (cfg ClassifierCatalogerConfig) MarshalJSON() ([]byte, error) {
// only keep the class names
var names []string
for _, cls := range cfg.Classifiers {
+33 -19
View File
@@ -21,6 +21,8 @@ import (
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/binary/test-fixtures/manager/testutil"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/source/directorysource"
"github.com/anchore/syft/syft/source/stereoscopesource"
)
var mustUseOriginalBinaries = flag.Bool("must-use-original-binaries", false, "force the use of binaries for testing (instead of snippets)")
@@ -862,6 +864,17 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
Metadata: metadata("openssl-binary"),
},
},
{
logicalFixture: "openssl/1.1.1w/linux-arm64",
expected: pkg.Package{
Name: "openssl",
Version: "1.1.1w",
Type: "binary",
PURL: "pkg:generic/openssl@1.1.1w",
Locations: locations("openssl"),
Metadata: metadata("openssl-binary"),
},
},
{
logicalFixture: "gcc/12.3.0/linux-amd64",
expected: pkg.Package{
@@ -888,7 +901,7 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
for _, test := range tests {
t.Run(test.logicalFixture, func(t *testing.T) {
c := NewCataloger(DefaultCatalogerConfig())
c := NewClassifierCataloger(DefaultClassifierCatalogerConfig())
// logicalFixture is the logical path to the full binary or snippet. This is relative to the test-fixtures/classifiers/snippets
// or test-fixtures/classifiers/bin directory . Snippets are searched for first, and if not found, then existing binaries are
@@ -896,7 +909,7 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
// full binaries are tested (no snippets), and if no binary is found the test will be skipped.
path := testutil.SnippetOrBinary(t, test.logicalFixture, *mustUseOriginalBinaries)
src, err := source.NewFromDirectoryPath(path)
src, err := directorysource.NewFromPath(path)
require.NoError(t, err)
resolver, err := src.FileResolver(source.SquashedScope)
@@ -933,11 +946,12 @@ func Test_Cataloger_DefaultClassifiers_PositiveCases_Image(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
c := NewCataloger(DefaultCatalogerConfig())
c := NewClassifierCataloger(DefaultClassifierCatalogerConfig())
img := imagetest.GetFixtureImage(t, "docker-archive", test.fixtureImage)
src, err := source.NewFromStereoscopeImageObject(img, test.fixtureImage, nil)
require.NoError(t, err)
src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
Reference: test.fixtureImage,
})
resolver, err := src.FileResolver(source.SquashedScope)
require.NoError(t, err)
@@ -964,9 +978,9 @@ func Test_Cataloger_DefaultClassifiers_PositiveCases_Image(t *testing.T) {
}
func TestClassifierCataloger_DefaultClassifiers_NegativeCases(t *testing.T) {
c := NewCataloger(DefaultCatalogerConfig())
c := NewClassifierCataloger(DefaultClassifierCatalogerConfig())
src, err := source.NewFromDirectoryPath("test-fixtures/classifiers/negative")
src, err := directorysource.NewFromPath("test-fixtures/classifiers/negative")
assert.NoError(t, err)
resolver, err := src.FileResolver(source.SquashedScope)
@@ -1006,13 +1020,13 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
tests := []struct {
name string
config CatalogerConfig
config ClassifierCatalogerConfig
fixtureDir string
expected *pkg.Package
}{
{
name: "empty-negative",
config: CatalogerConfig{
config: ClassifierCatalogerConfig{
Classifiers: []Classifier{},
},
fixtureDir: "test-fixtures/custom/go-1.14",
@@ -1020,7 +1034,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
},
{
name: "default-positive",
config: CatalogerConfig{
config: ClassifierCatalogerConfig{
Classifiers: defaultClassifers,
},
fixtureDir: "test-fixtures/custom/go-1.14",
@@ -1028,7 +1042,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
},
{
name: "nodefault-negative",
config: CatalogerConfig{
config: ClassifierCatalogerConfig{
Classifiers: []Classifier{fooClassifier},
},
fixtureDir: "test-fixtures/custom/go-1.14",
@@ -1036,7 +1050,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
},
{
name: "default-extended-positive",
config: CatalogerConfig{
config: ClassifierCatalogerConfig{
Classifiers: append(
append([]Classifier{}, defaultClassifers...),
fooClassifier,
@@ -1047,7 +1061,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
},
{
name: "default-custom-negative",
config: CatalogerConfig{
config: ClassifierCatalogerConfig{
Classifiers: append(
append([]Classifier{}, defaultClassifers...),
@@ -1066,7 +1080,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
},
{
name: "default-cutsom-positive",
config: CatalogerConfig{
config: ClassifierCatalogerConfig{
Classifiers: append(
append([]Classifier{}, defaultClassifers...),
fooClassifier,
@@ -1078,9 +1092,9 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
c := NewCataloger(test.config)
c := NewClassifierCataloger(test.config)
src, err := source.NewFromDirectoryPath(test.fixtureDir)
src, err := directorysource.NewFromPath(test.fixtureDir)
require.NoError(t, err)
resolver, err := src.FileResolver(source.SquashedScope)
@@ -1249,7 +1263,7 @@ func (p *panicyResolver) FileMetadataByLocation(_ file.Location) (file.Metadata,
var _ file.Resolver = (*panicyResolver)(nil)
func Test_Cataloger_ResilientToErrors(t *testing.T) {
c := NewCataloger(DefaultCatalogerConfig())
c := NewClassifierCataloger(DefaultClassifierCatalogerConfig())
resolver := &panicyResolver{}
_, _, err := c.Catalog(context.Background(), resolver)
@@ -1261,13 +1275,13 @@ func TestCatalogerConfig_MarshalJSON(t *testing.T) {
tests := []struct {
name string
cfg CatalogerConfig
cfg ClassifierCatalogerConfig
want string
wantErr assert.ErrorAssertionFunc
}{
{
name: "only show names of classes",
cfg: CatalogerConfig{
cfg: ClassifierCatalogerConfig{
Classifiers: []Classifier{
{
Class: "class",

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