mirror of
https://github.com/anchore/syft.git
synced 2026-10-12 06:07:20 +02:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e21379492 |
+4
-4
@@ -26,7 +26,7 @@ tools:
|
||||
# used for linting
|
||||
- name: golangci-lint
|
||||
version:
|
||||
want: v1.59.0
|
||||
want: v1.57.2
|
||||
method: github-release
|
||||
with:
|
||||
repo: golangci/golangci-lint
|
||||
@@ -58,7 +58,7 @@ tools:
|
||||
# used to release all artifacts
|
||||
- name: goreleaser
|
||||
version:
|
||||
want: v1.26.2
|
||||
want: v1.25.1
|
||||
method: github-release
|
||||
with:
|
||||
repo: goreleaser/goreleaser
|
||||
@@ -103,7 +103,7 @@ tools:
|
||||
# used for running all local and CI tasks
|
||||
- name: task
|
||||
version:
|
||||
want: v3.37.2
|
||||
want: v3.36.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: go-task/task
|
||||
@@ -111,7 +111,7 @@ tools:
|
||||
# used for triggering a release
|
||||
- name: gh
|
||||
version:
|
||||
want: v2.49.2
|
||||
want: v2.48.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: cli/cli
|
||||
|
||||
@@ -27,7 +27,7 @@ runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# note: go mod and build is automatically cached on default with v4+
|
||||
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 #v5.0.1
|
||||
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0
|
||||
if: inputs.go-version != ''
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
set -ue
|
||||
|
||||
BIN="syft"
|
||||
VERSION_FILE="VERSION"
|
||||
VERSION=$1
|
||||
DISTDIR=$1
|
||||
VERSION=$2
|
||||
|
||||
# the source of truth as to whether we want to notify users of an update is if the release just created is NOT
|
||||
# flagged as a pre-release on github
|
||||
@@ -12,9 +12,10 @@ if [[ "$(curl -SsL https://api.github.com/repos/anchore/${BIN}/releases/tags/${V
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "creating and publishing version file (${VERSION})"
|
||||
echo "creating and publishing version file"
|
||||
|
||||
# create a version file for version-update checks
|
||||
VERSION_FILE="${DISTDIR}/VERSION"
|
||||
echo "${VERSION}" | tee "${VERSION_FILE}"
|
||||
|
||||
# upload the version file that supports the application version update check
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
# the job by event.
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 #v5.0.1
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@9fdb3e49720b44c48891d036bb502feb25684276 #v3.25.6
|
||||
uses: github/codeql-action/init@d39d31e687223d841ef683f52467bd88e9b21c14 #v3.25.3
|
||||
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@9fdb3e49720b44c48891d036bb502feb25684276 #v3.25.6
|
||||
uses: github/codeql-action/autobuild@d39d31e687223d841ef683f52467bd88e9b21c14 #v3.25.3
|
||||
|
||||
# ℹ️ 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@9fdb3e49720b44c48891d036bb502feb25684276 #v3.25.6
|
||||
uses: github/codeql-action/analyze@d39d31e687223d841ef683f52467bd88e9b21c14 #v3.25.3
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- run: python .github/scripts/labeler.py
|
||||
env:
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
name: "Release Homebrew"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
|
||||
jobs:
|
||||
homebrew:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
with:
|
||||
# we need to be able to get the commit for a tag
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get release info
|
||||
id: release_info
|
||||
run: |
|
||||
echo -n "tag_name=$(gh release view --json tagName --jq '.tagName')" | tee -a $GITHUB_OUTPUT
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get commit info
|
||||
id: git_info
|
||||
run: |
|
||||
git checkout ${{ steps.release_info.outputs.tag_name }}
|
||||
echo -n "commit=$(git rev-parse HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
|
||||
- name: Update Homebrew formula
|
||||
uses: dawidd6/action-homebrew-bump-formula@baf2b60c51fc1f8453c884b0c61052668a71bd1d # v3.11.0
|
||||
with:
|
||||
token: ${{ secrets.HOMEBREW_TOKEN }}
|
||||
org: anchore
|
||||
formula: syft
|
||||
tag: ${{ steps.release_info.outputs.tag_name }}
|
||||
revision: ${{ steps.git_info.outputs.commit }}
|
||||
|
||||
- uses: 8398a7/action-slack@28ba43ae48961b90635b50953d216767a6bea486 #v3.16.2
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
fields: repo,workflow,action,eventName
|
||||
text: "Post-release homebrew publish workflow has failed: https://github.com/anchore/syft/actions/workflows/release-homebrew.yaml"
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
|
||||
@@ -1,31 +0,0 @@
|
||||
name: "Release"
|
||||
|
||||
on:
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: release version to update the version file with (prefixed with v)
|
||||
required: true
|
||||
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
type: string
|
||||
description: release version to update the version file with (prefixed with v)
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
|
||||
- name: Update version file
|
||||
run: make ci-release-version-file
|
||||
env:
|
||||
RELEASE_VERSION: ${{ github.event.inputs.version }}
|
||||
# for updating the VERSION file in S3...
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
environment: release
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Check if tag already exists
|
||||
# note: this will fail if the tag already exists
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
# required for goreleaser signs section with cosign
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -105,13 +105,13 @@ jobs:
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 #v3.2.0
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 #v3.1.0
|
||||
with:
|
||||
username: ${{ secrets.ANCHOREOSSWRITE_DH_USERNAME }}
|
||||
password: ${{ secrets.ANCHOREOSSWRITE_DH_PAT }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 #v3.2.0
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 #v3.1.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -139,8 +139,11 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# for updating brew formula in anchore/homebrew-syft
|
||||
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
|
||||
# for updating the VERSION file in S3...
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
|
||||
|
||||
- uses: anchore/sbom-action@e8d2a6937ecead383dfe75190d104edd1f9c5751 #v0.16.0
|
||||
- uses: anchore/sbom-action@7ccf588e3cf3cc2611714c2eeae48550fbc17552 #v0.15.11
|
||||
continue-on-error: true
|
||||
with:
|
||||
artifact-name: sbom.spdx.json
|
||||
@@ -154,10 +157,3 @@ jobs:
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
|
||||
if: ${{ success() }}
|
||||
|
||||
release-version-file:
|
||||
needs: [release]
|
||||
uses: ./.github/workflows/release-version-file.yaml
|
||||
with:
|
||||
version: ${{ github.event.inputs.version }}
|
||||
secrets: inherit
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 #v5.0.1
|
||||
with:
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
name: "Static analysis"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
name: "Unit tests"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
name: "Integration tests"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
name: "Build snapshot artifacts"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -139,7 +139,7 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -187,7 +187,7 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -195,6 +195,7 @@ jobs:
|
||||
bootstrap-apt-packages: ""
|
||||
compute-fingerprints: "false"
|
||||
go-dependencies: false
|
||||
go-version: ""
|
||||
|
||||
- name: Download snapshot build
|
||||
id: snapshot-cache
|
||||
@@ -231,7 +232,7 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
@@ -52,15 +52,10 @@ linters-settings:
|
||||
gocritic:
|
||||
enabled-checks:
|
||||
- deferInLoop
|
||||
- ruleguard
|
||||
settings:
|
||||
ruleguard:
|
||||
rules: "test/rules/rules.go"
|
||||
output:
|
||||
uniq-by-line: false
|
||||
run:
|
||||
timeout: 10m
|
||||
tests: false
|
||||
|
||||
# do not enable...
|
||||
# - deadcode # The owner seems to have abandoned the linter. Replaced by "unused".
|
||||
|
||||
@@ -2,27 +2,25 @@
|
||||
<img src="https://user-images.githubusercontent.com/5199289/136844524-1527b09f-c5cb-4aa9-be54-5aa92a6086c1.png" width="271" alt="Cute pink owl syft logo">
|
||||
</p>
|
||||
|
||||
# Syft
|
||||
[](https://github.com/anchore/syft/actions/workflows/validations.yaml)
|
||||
[](https://goreportcard.com/report/github.com/anchore/syft)
|
||||
[](https://github.com/anchore/syft/releases/latest)
|
||||
[](https://github.com/anchore/syft)
|
||||
[](https://github.com/anchore/syft/blob/main/LICENSE)
|
||||
[](https://anchore.com/slack)
|
||||
|
||||
**A CLI tool and Go library for generating a Software Bill of Materials (SBOM) from container images and filesystems. Exceptional for vulnerability detection when used with a scanner like [Grype](https://github.com/anchore/grype).**
|
||||
A CLI tool and Go library for generating a Software Bill of Materials (SBOM) from container images and filesystems. Exceptional for vulnerability detection when used with a scanner like [Grype](https://github.com/anchore/grype).
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/anchore/syft/actions/workflows/validations.yaml" target="_blank"><img alt="Validations" src="https://github.com/anchore/syft/actions/workflows/validations.yaml/badge.svg"></a>
|
||||
<a href="https://goreportcard.com/report/github.com/anchore/syft" target="_blank"><img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/anchore/syft"></a>
|
||||
<a href="https://github.com/anchore/syft/releases/latest" target="_blank"><img alt="GitHub release" src="https://img.shields.io/github/release/anchore/syft.svg"></a>
|
||||
<a href="https://github.com/anchore/syft" target="_blank"><img alt="GitHub go.mod Go version" src="https://img.shields.io/github/go-mod/go-version/anchore/syft.svg"></a>
|
||||
<a href"" target="_blank"><img alt="License: Apache-2.0" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a>
|
||||
<a href="https://anchore.com/slack" target="_blank"><img alt="Slack" src="https://img.shields.io/badge/Slack-Join-blue?logo=slack"></a>
|
||||
</p>
|
||||
### Join our community meetings!
|
||||
|
||||
- Calendar: https://calendar.google.com/calendar/u/0/r?cid=Y182OTM4dGt0MjRtajI0NnNzOThiaGtnM29qNEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t
|
||||
- Agenda: https://docs.google.com/document/d/1ZtSAa6fj2a6KRWviTn3WoJm09edvrNUp4Iz_dOjjyY8/edit?usp=sharing (join [this group](https://groups.google.com/g/anchore-oss-community) for write access)
|
||||
- All are welcome!
|
||||
|
||||
For commercial support options with Syft or Grype, please [contact Anchore](https://get.anchore.com/contact/)
|
||||
|
||||

|
||||
|
||||
## Introduction
|
||||
|
||||
Syft is a powerful and easy-to-use open-source tool for generating Software Bill of Materials (SBOMs) for container images and filesystems. It provides detailed visibility into the packages and dependencies in your software, helping you manage vulnerabilities, license compliance, and software supply chain security.
|
||||
|
||||
Syft development is sponsored by [Anchore](https://anchore.com/), and is released under the [Apache-2.0 License](https://github.com/anchore/syft?tab=Apache-2.0-1-ov-file). For commercial support options with Syft or Grype, please [contact Anchore](https://get.anchore.com/contact/).
|
||||
|
||||
## Features
|
||||
- Generates SBOMs for container images, filesystems, archives, and more to discover packages and libraries
|
||||
- Supports OCI, Docker and [Singularity](https://github.com/sylabs/singularity) image formats
|
||||
@@ -31,91 +29,6 @@ Syft development is sponsored by [Anchore](https://anchore.com/), and is release
|
||||
- Able to create signed SBOM attestations using the [in-toto specification](https://github.com/in-toto/attestation/blob/main/spec/README.md)
|
||||
- Convert between SBOM formats, such as CycloneDX, SPDX, and Syft's own format.
|
||||
|
||||
## Installation
|
||||
|
||||
Syft binaries are provided for Linux, macOS and Windows.
|
||||
|
||||
### Recommended
|
||||
> ```bash
|
||||
> curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
|
||||
> ```
|
||||
|
||||
... or, you can specify a release version and destination directory for the installation:
|
||||
|
||||
> ```bash
|
||||
> curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b <DESTINATION_DIR> <RELEASE_VERSION>
|
||||
> ```
|
||||
|
||||
### Homebrew
|
||||
```bash
|
||||
brew install syft
|
||||
```
|
||||
|
||||
### Scoop
|
||||
|
||||
```powershell
|
||||
scoop install syft
|
||||
```
|
||||
|
||||
### Chocolatey
|
||||
|
||||
The chocolatey distribution of Syft is community-maintained and not distributed by the Anchore team
|
||||
|
||||
```powershell
|
||||
choco install syft -y
|
||||
```
|
||||
|
||||
### Nix
|
||||
|
||||
**Note**: Nix packaging of Syft is [community maintained](https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/admin/syft/default.nix). Syft is available in the [stable channel](https://wiki.nixos.org/wiki/Nix_channels#The_official_channels) since NixOS `22.05`.
|
||||
|
||||
```bash
|
||||
nix-env -i syft
|
||||
```
|
||||
|
||||
... or, just try it out in an ephemeral nix shell:
|
||||
|
||||
```bash
|
||||
nix-shell -p syft
|
||||
```
|
||||
|
||||
## Getting started
|
||||
|
||||
### SBOM
|
||||
|
||||
To generate an SBOM for a container image:
|
||||
|
||||
```bash
|
||||
syft <image>
|
||||
```
|
||||
|
||||
The above output includes only software that is visible in the container (i.e., the squashed representation of the image). To include software from all image layers in the SBOM, regardless of its presence in the final image, provide `--scope all-layers`:
|
||||
|
||||
```bash
|
||||
syft <image> --scope all-layers
|
||||
```
|
||||
|
||||
### Output formats
|
||||
|
||||
The output format for Syft is configurable as well using the `-o` (or `--output`) option:
|
||||
|
||||
```
|
||||
syft <image> -o <format>
|
||||
```
|
||||
|
||||
Where the `formats` available are:
|
||||
- `syft-json`: Use this to get as much information out of Syft as possible!
|
||||
- `syft-text`: A row-oriented, human-and-machine-friendly output.
|
||||
- `cyclonedx-xml`: A XML report conforming to the [CycloneDX 1.4 specification](https://cyclonedx.org/specification/overview/).
|
||||
- `cyclonedx-json`: A JSON report conforming to the [CycloneDX 1.4 specification](https://cyclonedx.org/specification/overview/).
|
||||
- `spdx-tag-value`: A tag-value formatted report conforming to the [SPDX 2.3 specification](https://spdx.github.io/spdx-spec/v2.3/).
|
||||
- `spdx-tag-value@2.2`: A tag-value formatted report conforming to the [SPDX 2.2 specification](https://spdx.github.io/spdx-spec/v2.2.2/).
|
||||
- `spdx-json`: A JSON report conforming to the [SPDX 2.3 JSON Schema](https://github.com/spdx/spdx-spec/blob/v2.3/schemas/spdx-schema.json).
|
||||
- `spdx-json@2.2`: A JSON report conforming to the [SPDX 2.2 JSON Schema](https://github.com/spdx/spdx-spec/blob/v2.2/schemas/spdx-schema.json).
|
||||
- `github-json`: A JSON report conforming to GitHub's dependency snapshot format.
|
||||
- `syft-table`: A columnar summary (default).
|
||||
- `template`: Lets the user specify the output format. See ["Using templates"](#using-templates) below.
|
||||
|
||||
### Supported Ecosystems
|
||||
|
||||
- Alpine (apk)
|
||||
@@ -143,31 +56,816 @@ Where the `formats` available are:
|
||||
- Swift (cocoapods, swift-package-manager)
|
||||
- Wordpress plugins
|
||||
|
||||
## Documentation
|
||||
## Installation
|
||||
|
||||
Our [wiki](https://github.com/anchore/syft/wiki) contains further details on the following topics:
|
||||
**Note**: Currently, Syft is built only for Linux, macOS and Windows.
|
||||
|
||||
* [Supported Sources](https://github.com/anchore/syft/wiki/supported-sources)
|
||||
* [File Selection](https://github.com/anchore/syft/wiki/file-selection)
|
||||
* [Excluding file paths](https://github.com/anchore/syft/wiki/excluding-file-paths)
|
||||
* [Output formats](https://github.com/anchore/syft/wiki/output-formats)
|
||||
* [Package Cataloger Selection](https://github.com/anchore/syft/wiki/package-cataloger-selection)
|
||||
* [Concepts](https://github.com/anchore/syft/wiki/package-cataloger-selection#concepts)
|
||||
* [Examples](https://github.com/anchore/syft/wiki/package-cataloger-selection#examples)
|
||||
* [Using templates](https://github.com/anchore/syft/wiki/using-templates)
|
||||
* [Multiple outputs](https://github.com/anchore/syft/wiki/multiple-outputs)
|
||||
* [Private Registry Authentication](https://github.com/anchore/syft/wiki/private-registry-authentication)
|
||||
* [Local Docker Credentials](https://github.com/anchore/syft/wiki/private-registry-authentication#local-docker)
|
||||
* [Docker Credentials in Kubernetes](https://github.com/anchore/syft/wiki/private-registry-authentication#docker-credentials-in-kubernetes)
|
||||
* [Attestation (experimental)](https://github.com/anchore/syft/wiki/attestation)
|
||||
* [Keyless Support](https://github.com/anchore/syft/wiki/attestation#keyless-support)
|
||||
* [Local private key support](https://github.com/anchore/syft/wiki/attestation#local-private-key-support)
|
||||
* [Adding an SBOM to an image as an attestation using Syft](https://github.com/anchore/syft/wiki/attestation#adding-an-sbom-to-an-image-as-an-attestation-using-syft)
|
||||
* [Configuration](https://github.com/anchore/syft/wiki/configuration)
|
||||
### Recommended
|
||||
```bash
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
|
||||
```
|
||||
|
||||
## Syft Team Meetings
|
||||
... or, you can specify a release version and destination directory for the installation:
|
||||
|
||||
The Syft Team hold regular community meetings online. All are welcome to join to bring topics for discussion.
|
||||
- Check the [calendar](https://calendar.google.com/calendar/u/0/r?cid=Y182OTM4dGt0MjRtajI0NnNzOThiaGtnM29qNEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t) for the next meeting date.
|
||||
- Add items to the [agenda](https://docs.google.com/document/d/1ZtSAa6fj2a6KRWviTn3WoJm09edvrNUp4Iz_dOjjyY8/edit?usp=sharing) (join [this group](https://groups.google.com/g/anchore-oss-community) for write access to the [agenda](https://docs.google.com/document/d/1ZtSAa6fj2a6KRWviTn3WoJm09edvrNUp4Iz_dOjjyY8/edit?usp=sharing))
|
||||
- See you there!
|
||||
```
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b <DESTINATION_DIR> <RELEASE_VERSION>
|
||||
```
|
||||
|
||||
### Chocolatey
|
||||
|
||||
The chocolatey distribution of syft is community maintained and not distributed by the anchore team
|
||||
|
||||
```powershell
|
||||
choco install syft -y
|
||||
```
|
||||
|
||||
### Scoop
|
||||
|
||||
```powershell
|
||||
scoop install syft
|
||||
```
|
||||
|
||||
### Homebrew
|
||||
```bash
|
||||
brew install syft
|
||||
```
|
||||
|
||||
### Nix
|
||||
|
||||
**Note**: Nix packaging of Syft is [community maintained](https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/admin/syft/default.nix). Syft is available in the [stable channel](https://nixos.wiki/wiki/Nix_channels#The_official_channels) since NixOS `22.05`.
|
||||
|
||||
```bash
|
||||
nix-env -i syft
|
||||
```
|
||||
|
||||
... or, just try it out in an ephemeral nix shell:
|
||||
|
||||
```bash
|
||||
nix-shell -p syft
|
||||
```
|
||||
|
||||
## Getting started
|
||||
|
||||
### SBOM
|
||||
|
||||
To generate an SBOM for a container image:
|
||||
|
||||
```bash
|
||||
syft <image>
|
||||
```
|
||||
|
||||
The above output includes only software that is visible in the container (i.e., the squashed representation of the image). To include software from all image layers in the SBOM, regardless of its presence in the final image, provide `--scope all-layers`:
|
||||
|
||||
```bash
|
||||
syft <image> --scope all-layers
|
||||
```
|
||||
|
||||
### Supported 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)
|
||||
syft path/to/image.tar
|
||||
|
||||
# catalog a Singularity Image Format (SIF) container
|
||||
syft path/to/image.sif
|
||||
|
||||
# catalog a directory
|
||||
syft path/to/dir
|
||||
```
|
||||
|
||||
To explicitly specify the source behavior, use the `--from` flag. Allowable options are:
|
||||
|
||||
```
|
||||
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.
|
||||
|
||||
This default behavior can be overridden with the `default-image-pull-source` configuration option (See [Configuration](#configuration) for more details).
|
||||
|
||||
|
||||
### File selection
|
||||
|
||||
By default, Syft will catalog file details and digests for files that are owned by discovered packages. You can change this behavior by using the `SYFT_FILE_METADATA_SELECTION` environment variable or the `file.metadata.selection` configuration option. The options are:
|
||||
|
||||
- `all`: capture all files from the search space
|
||||
- `owned-by-package`: capture only files owned by packages (default)
|
||||
- `none`: disable capturing any file information
|
||||
|
||||
|
||||
### Package cataloger selection
|
||||
|
||||
#### Concepts
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Syft uses a different set of catalogers by default when scanning files directly than it does when scanning images
|
||||
|
||||
The catalogers for an image scan assumes that package installation steps have already been completed. For example, Syft will identify Python packages that have egg or wheel metadata files under a `site-packages` directory, since this is how the canonical tooling `pip` installs python packages.
|
||||
|
||||
The catalogers for a directory scan will look for installed software as well as declared dependencies that are not necessarily installed. For example, dependencies listed in a Python `requirements.txt`.
|
||||
|
||||
This default set of catalogers being dynamic is critical as this allows Syft to be used in a variety of contexts while still generating accurate SBOMs.
|
||||
Overriding the set of default catalogers is not recommended for most purposes, however, is possible if needed.
|
||||
|
||||
Catalogers can be referenced in two different ways:
|
||||
- *by name*: the exact cataloger name (e.g. `java-pom-cataloger` or `java-archive-cataloger`)
|
||||
- *by tag*: a tag that is associated with a cataloger (e.g. `java`)
|
||||
|
||||
Syft can take lists of references on the CLI or in the application configuration to define which catalogers to use.
|
||||
|
||||
You can **set** the list of catalogers explicitly to use with the `--override-default-catalogers` CLI flag, accepting a comma-separated list of cataloger names or tags.
|
||||
|
||||
You can also **add** to, **remove** from, or **sub-select** catalogers to use within the default set of catalogers by using the `--select-catalogers` CLI flag.
|
||||
- To **sub-select** catalogers simply provide a tag (e.g. `--select-catalogers TAG`). Catalogers will always be selected from the default set of catalogers (e.g. `--select-catalogers java,go` will select all the `java` catalogers in the default set and all the `go` catalogers in the default set).
|
||||
- To **add** a cataloger prefix the cataloger name with `+` (e.g. `--select-catalogers +NAME`). Added catalogers will _always be added_ regardless of removals, filtering, or other defaults.
|
||||
- To **remove** a cataloger prefix the cataloger name or tag with `-` (e.g. `--select-catalogers -NAME_OR_TAG`). Catalogers are removed from the set of default catalogers after processing any sub-selections.
|
||||
|
||||
These rules and the dynamic default cataloger sets approximates to the following logic:
|
||||
|
||||
```
|
||||
image_catalogers = all_catalogers AND catalogers_tagged("image")
|
||||
|
||||
directory_catalogers = all_catalogers AND catalogers_tagged("directory")
|
||||
|
||||
default_catalogers = image_catalogers OR directory_catalogers
|
||||
|
||||
sub_selected_catalogers = default_catalogers INTERSECT catalogers_tagged(TAG) [ UNION sub_selected_catalogers ... ]
|
||||
|
||||
base_catalogers = default_catalogers OR sub_selected_catalogers
|
||||
|
||||
final_set = (base_catalogers SUBTRACT removed_catalogers) UNION added_catalogers
|
||||
```
|
||||
|
||||
|
||||
#### Examples
|
||||
|
||||
Only scan for python related packages with catalogers appropriate for the source type (image or directory):
|
||||
```bash
|
||||
syft <some container image> --select-catalogers "python"
|
||||
# results in the following catalogers being used:
|
||||
# - python-installed-package-cataloger
|
||||
```
|
||||
|
||||
Same command, but the set of catalogers changes based on what is being analyzed (in this case a directory):
|
||||
```bash
|
||||
syft <a directory> --select-catalogers "python"
|
||||
# results in the following catalogers being used:
|
||||
# - python-installed-package-cataloger
|
||||
# - python-package-cataloger
|
||||
```
|
||||
|
||||
Use the default set of catalogers and add a cataloger to the set:
|
||||
```bash
|
||||
syft ... --select-catalogers "+sbom-cataloger"
|
||||
```
|
||||
|
||||
Use the default set of catalogers but remove any catalogers that deal with RPMs:
|
||||
```bash
|
||||
syft ... --select-catalogers "-rpm"
|
||||
```
|
||||
|
||||
Only scan with catalogers that:
|
||||
- are tagged with "go"
|
||||
- always use the sbom-cataloger
|
||||
- are appropriate for the source type (image or directory)
|
||||
|
||||
```bash
|
||||
syft <some container image> --select-catalogers "go,+sbom-cataloger"
|
||||
# results in the following catalogers being used:
|
||||
# - go-module-binary-cataloger
|
||||
# - sbom-cataloger
|
||||
```
|
||||
|
||||
Scan with all catalogers that deal with binary analysis, regardless of the source type:
|
||||
```bash
|
||||
syft ... --override-default-catalogers "binary"
|
||||
# results in the following catalogers being used:
|
||||
# - binary-cataloger
|
||||
# - cargo-auditable-binary-cataloger
|
||||
# - dotnet-portable-executable-cataloger
|
||||
# - go-module-binary-cataloger
|
||||
```
|
||||
|
||||
Only scan with the specific `go-module-binary-cataloger` and `go-module-file-cataloger` catalogers:
|
||||
```bash
|
||||
syft ... --override-default-catalogers "go-module-binary-cataloger,go-module-file-cataloger"
|
||||
```
|
||||
|
||||
|
||||
### Excluding file paths
|
||||
|
||||
Syft can exclude files and paths from being scanned within a source by using glob expressions
|
||||
with one or more `--exclude` parameters:
|
||||
```
|
||||
syft <source> --exclude './out/**/*.json' --exclude /etc
|
||||
```
|
||||
**Note:** in the case of _image scanning_, since the entire filesystem is scanned it is
|
||||
possible to use absolute paths like `/etc` or `/usr/**/*.txt` whereas _directory scans_
|
||||
exclude files _relative to the specified directory_. For example: scanning `/usr/foo` with
|
||||
`--exclude ./package.json` would exclude `/usr/foo/package.json` and `--exclude '**/package.json'`
|
||||
would exclude all `package.json` files under `/usr/foo`. For _directory scans_,
|
||||
it is required to begin path expressions with `./`, `*/`, or `**/`, all of which
|
||||
will be resolved _relative to the specified scan directory_. Keep in mind, your shell
|
||||
may attempt to expand wildcards, so put those parameters in single quotes, like:
|
||||
`'**/*.json'`.
|
||||
|
||||
### Output formats
|
||||
|
||||
The output format for Syft is configurable as well using the
|
||||
`-o` (or `--output`) option:
|
||||
|
||||
```
|
||||
syft <image> -o <format>
|
||||
```
|
||||
|
||||
Where the `formats` available are:
|
||||
- `syft-json`: Use this to get as much information out of Syft as possible!
|
||||
- `syft-text`: A row-oriented, human-and-machine-friendly output.
|
||||
- `cyclonedx-xml`: A XML report conforming to the [CycloneDX 1.4 specification](https://cyclonedx.org/specification/overview/).
|
||||
- `cyclonedx-json`: A JSON report conforming to the [CycloneDX 1.4 specification](https://cyclonedx.org/specification/overview/).
|
||||
- `spdx-tag-value`: A tag-value formatted report conforming to the [SPDX 2.3 specification](https://spdx.github.io/spdx-spec/v2.3/).
|
||||
- `spdx-tag-value@2.2`: A tag-value formatted report conforming to the [SPDX 2.2 specification](https://spdx.github.io/spdx-spec/v2.2.2/).
|
||||
- `spdx-json`: A JSON report conforming to the [SPDX 2.3 JSON Schema](https://github.com/spdx/spdx-spec/blob/v2.3/schemas/spdx-schema.json).
|
||||
- `spdx-json@2.2`: A JSON report conforming to the [SPDX 2.2 JSON Schema](https://github.com/spdx/spdx-spec/blob/v2.2/schemas/spdx-schema.json).
|
||||
- `github-json`: A JSON report conforming to GitHub's dependency snapshot format.
|
||||
- `syft-table`: A columnar summary (default).
|
||||
- `template`: Lets the user specify the output format. See ["Using templates"](#using-templates) below.
|
||||
|
||||
## Using templates
|
||||
|
||||
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.
|
||||
|
||||
- Set the output format to "template" (`-o template`).
|
||||
|
||||
- Specify the path to the template file (`-t ./path/to/custom.template`).
|
||||
|
||||
- Syft's template processing uses the same data models as the `syft-json` output format — so if you're wondering what data is available as you author a template, you can use the output from `syft <image> -o syft-json` as a reference.
|
||||
|
||||
**Example:** You could make Syft output data in CSV format by writing a Go template that renders CSV data and then running `syft <image> -o template -t ~/path/to/csv.tmpl`.
|
||||
|
||||
Here's what the `csv.tmpl` file might look like:
|
||||
```gotemplate
|
||||
"Package","Version Installed", "Found by"
|
||||
{{- range .artifacts}}
|
||||
"{{.name}}","{{.version}}","{{.foundBy}}"
|
||||
{{- end}}
|
||||
```
|
||||
|
||||
Which would produce output like:
|
||||
```text
|
||||
"Package","Version Installed","Found by"
|
||||
"alpine-baselayout","3.2.0-r20","apkdb-cataloger"
|
||||
"alpine-baselayout-data","3.2.0-r20","apkdb-cataloger"
|
||||
"alpine-keys","2.4-r1","apkdb-cataloger"
|
||||
...
|
||||
```
|
||||
|
||||
Syft also includes a vast array of utility templating functions from [sprig](http://masterminds.github.io/sprig/) apart from the default Golang [text/template](https://pkg.go.dev/text/template#hdr-Functions) to allow users to customize the output format.
|
||||
|
||||
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
|
||||
`=<file>` to the option, for example to output Syft JSON and SPDX JSON:
|
||||
|
||||
```shell
|
||||
syft <image> -o syft-json=sbom.syft.json -o spdx-json=sbom.spdx.json
|
||||
```
|
||||
|
||||
## Private Registry Authentication
|
||||
|
||||
### Local Docker Credentials
|
||||
When a container runtime is not present, Syft can still utilize credentials configured in common credential sources (such as `~/.docker/config.json`). It will pull images from private registries using these credentials. The config file is where your credentials are stored when authenticating with private registries via some command like `docker login`. For more information see the `go-containerregistry` [documentation](https://github.com/google/go-containerregistry/tree/main/pkg/authn).
|
||||
|
||||
An example `config.json` looks something like this:
|
||||
```json
|
||||
{
|
||||
"auths": {
|
||||
"registry.example.com": {
|
||||
"username": "AzureDiamond",
|
||||
"password": "hunter2"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can run the following command as an example. It details the mount/environment configuration a container needs to access a private registry:
|
||||
|
||||
```
|
||||
docker run -v ./config.json:/config/config.json -e "DOCKER_CONFIG=/config" anchore/syft:latest <private_image>
|
||||
```
|
||||
|
||||
### Docker Credentials in Kubernetes
|
||||
|
||||
Here's a simple workflow to mount this config file as a secret into a container on Kubernetes.
|
||||
|
||||
1. Create a secret. The value of `config.json` is important. It refers to the specification detailed [here](https://github.com/google/go-containerregistry/tree/main/pkg/authn#the-config-file). Below this section is the `secret.yaml` file that the pod configuration will consume as a volume. The key `config.json` is important. It will end up being the name of the file when mounted into the pod.
|
||||
|
||||
```yaml
|
||||
# secret.yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: registry-config
|
||||
namespace: syft
|
||||
data:
|
||||
config.json: <base64 encoded config.json>
|
||||
```
|
||||
|
||||
`kubectl apply -f secret.yaml`
|
||||
|
||||
|
||||
2. Create your pod running syft. The env `DOCKER_CONFIG` is important because it advertises where to look for the credential file. In the below example, setting `DOCKER_CONFIG=/config` informs syft that credentials can be found at `/config/config.json`. This is why we used `config.json` as the key for our secret. When mounted into containers the secrets' key is used as the filename. The `volumeMounts` section mounts our secret to `/config`. The `volumes` section names our volume and leverages the secret we created in step one.
|
||||
|
||||
```yaml
|
||||
# pod.yaml
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: syft-k8s-usage
|
||||
spec:
|
||||
containers:
|
||||
- image: anchore/syft:latest
|
||||
name: syft-private-registry-demo
|
||||
env:
|
||||
- name: DOCKER_CONFIG
|
||||
value: /config
|
||||
volumeMounts:
|
||||
- mountPath: /config
|
||||
name: registry-config
|
||||
readOnly: true
|
||||
args:
|
||||
- <private_image>
|
||||
volumes:
|
||||
- name: registry-config
|
||||
secret:
|
||||
secretName: registry-config
|
||||
```
|
||||
|
||||
`kubectl apply -f pod.yaml`
|
||||
|
||||
|
||||
3. The user can now run `kubectl logs syft-private-registry-demo`. The logs should show the Syft analysis for the `<private_image>` provided in the pod configuration.
|
||||
|
||||
Using the above information, users should be able to configure private registry access without having to do so in the `grype` or `syft` configuration files. They will also not be dependent on a Docker daemon, (or some other runtime software) for registry configuration and access.
|
||||
|
||||
## Format conversion (experimental)
|
||||
|
||||
The ability to convert existing SBOMs means you can create SBOMs in different formats quickly, without the need to regenerate the SBOM from scratch, which may take significantly more time.
|
||||
|
||||
```
|
||||
syft convert <ORIGINAL-SBOM-FILE> -o <NEW-SBOM-FORMAT>[=<NEW-SBOM-FILE>]
|
||||
```
|
||||
|
||||
This feature is experimental and data might be lost when converting formats. Packages are the main SBOM component easily transferable across formats, whereas files and relationships, as well as other information Syft doesn't support, are more likely to be lost.
|
||||
|
||||
We support formats with wide community usage AND good encode/decode support by Syft. The supported formats are:
|
||||
- Syft JSON (```-o syft-json```)
|
||||
- SPDX 2.2 JSON (```-o spdx-json```)
|
||||
- SPDX 2.2 tag-value (```-o spdx-tag-value```)
|
||||
- CycloneDX 1.4 JSON (```-o cyclonedx-json```)
|
||||
- CycloneDX 1.4 XML (```-o cyclonedx-xml```)
|
||||
|
||||
Conversion example:
|
||||
```sh
|
||||
syft alpine:latest -o syft-json=sbom.syft.json # generate a syft SBOM
|
||||
syft convert sbom.syft.json -o cyclonedx-json=sbom.cdx.json # convert it to CycloneDX
|
||||
```
|
||||
|
||||
## Attestation (experimental)
|
||||
### Keyless support
|
||||
Syft supports generating attestations using cosign's [keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) signatures.
|
||||
|
||||
Note: users need to have >= v1.12.0 of cosign installed for this command to function
|
||||
|
||||
To use this feature with a format like CycloneDX json simply run:
|
||||
```
|
||||
syft attest --output cyclonedx-json <IMAGE WITH OCI WRITE ACCESS>
|
||||
```
|
||||
This command will open a web browser and allow the user to authenticate their OIDC identity as the root of trust for the attestation (Github, Google, Microsoft).
|
||||
|
||||
After authenticating, Syft will upload the attestation to the OCI registry specified by the image that the user has write access to.
|
||||
|
||||
You will need to make sure your credentials are configured for the OCI registry you are uploading to so that the attestation can write successfully.
|
||||
|
||||
Users can then verify the attestation(or any image with attestations) by running:
|
||||
```
|
||||
COSIGN_EXPERIMENTAL=1 cosign verify-attestation <IMAGE_WITH_ATTESTATIONS>
|
||||
```
|
||||
|
||||
Users should see that the uploaded attestation claims are validated, the claims exist within the transparency log, and certificates on the attestations were verified against [fulcio](https://github.com/SigStore/fulcio).
|
||||
There will also be a printout of the certificates subject `<user identity>` and the certificate issuer URL: `<provider of user identity (Github, Google, Microsoft)>`:
|
||||
```
|
||||
Certificate subject: test.email@testdomain.com
|
||||
Certificate issuer URL: https://accounts.google.com
|
||||
```
|
||||
|
||||
### Local private key support
|
||||
|
||||
To generate an SBOM attestation for a container image using a local private key:
|
||||
```
|
||||
syft attest --output [FORMAT] --key [KEY] [SOURCE] [flags]
|
||||
```
|
||||
|
||||
The above output is in the form of the [DSSE envelope](https://github.com/secure-systems-lab/dsse/blob/master/envelope.md#dsse-envelope).
|
||||
The payload is a base64 encoded `in-toto` statement with the generated SBOM as the predicate. For details on workflows using this command see [here](#adding-an-sbom-to-an-image-as-an-attestation-using-syft).
|
||||
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration search paths:
|
||||
|
||||
- `.syft.yaml`
|
||||
- `.syft/config.yaml`
|
||||
- `~/.syft.yaml`
|
||||
- `<XDG_CONFIG_HOME>/syft/config.yaml`
|
||||
|
||||
Configuration options (example values are the default):
|
||||
|
||||
```yaml
|
||||
# the output format(s) of the SBOM report (options: syft-table, syft-text, syft-json, spdx-json, ...)
|
||||
# to specify multiple output files in differing formats, use a list:
|
||||
# output:
|
||||
# - "syft-json=<syft-json-output-file>"
|
||||
# - "spdx-json=<spdx-json-output-file>"
|
||||
# SYFT_OUTPUT env var / -o, --output flags
|
||||
output:
|
||||
- "syft-table"
|
||||
|
||||
# suppress all output (except for the SBOM report)
|
||||
# SYFT_QUIET env var / -q flag
|
||||
quiet: false
|
||||
|
||||
# enable/disable checking for application updates on startup
|
||||
# SYFT_CHECK_FOR_APP_UPDATE env var
|
||||
check-for-app-update: true
|
||||
|
||||
# maximum number of workers used to process the list of package catalogers in parallel
|
||||
parallelism: 1
|
||||
|
||||
# a list of globs to exclude from scanning, for example:
|
||||
# exclude:
|
||||
# - "/etc/**"
|
||||
# - "./out/**/*.json"
|
||||
# SYFT_EXCLUDE env var / --exclude flag
|
||||
exclude: []
|
||||
|
||||
# os and/or architecture to use when referencing container images (e.g. "windows/armv6" or "arm64")
|
||||
# SYFT_PLATFORM env var / --platform flag
|
||||
platform: ""
|
||||
|
||||
# the search space to look for file and package data (options: all-layers, squashed)
|
||||
# SYFT_SCOPE env var
|
||||
scope: "squashed"
|
||||
|
||||
# set the list of package catalogers to use when generating the SBOM
|
||||
# default = empty (cataloger set determined automatically by the source type [image or file/directory])
|
||||
# Use `syft cataloger list` for a list of catalogers you can specify
|
||||
# DEPRECATED: please use default-catalogers and select-catalogers configuration options instead
|
||||
# SYFT_CATALOGERS env var / --catalogers flag
|
||||
catalogers:
|
||||
|
||||
# set the base set of catalogers to use (defaults to 'image' or 'directory' depending on the scan source)
|
||||
# SYFT_DEFAULT_CATALOGERS env var / --override-default-catalogers flag
|
||||
default-catalogers: []
|
||||
|
||||
# add, remove, and filter the catalogers to be used
|
||||
# SYFT_SELECT_CATALOGERS env var / --select-catalogers flag;
|
||||
select-catalogers: []
|
||||
|
||||
# all format configuration
|
||||
format:
|
||||
|
||||
# default value for all formats that support the "pretty" option (default is unset)
|
||||
# SYFT_FORMAT_PRETTY env var
|
||||
pretty:
|
||||
|
||||
# all syft-json format options
|
||||
json:
|
||||
|
||||
# include space indention and newlines (inherits default value from 'format.pretty' or 'false' if parent is unset)
|
||||
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||
# SYFT_FORMAT_JSON_PRETTY env var
|
||||
pretty: false
|
||||
|
||||
# transform any syft-json output to conform to an approximation of the v11.0.1 schema. This includes:
|
||||
# - using the package metadata type names from before v12 of the JSON schema (changed in https://github.com/anchore/syft/pull/1983)
|
||||
#
|
||||
# Note: this will still include package types and fields that were added at or after json schema v12. This means
|
||||
# that output might not strictly be json schema v11 compliant, however, for consumers that require time to port
|
||||
# over to the final syft 1.0 json output this option can be used to ease the transition.
|
||||
#
|
||||
# Note: long term support for this option is not guaranteed (it may change or break at any time).
|
||||
# SYFT_FORMAT_JSON_LEGACY env var
|
||||
legacy: false
|
||||
|
||||
# all template format options
|
||||
template:
|
||||
# path to the template file to use when rendering the output with the `template` output format.
|
||||
# Note that all template paths are based on the current syft-json schema.
|
||||
# SYFT_FORMAT_TEMPLATE_PATH env var / -t flag
|
||||
path: ""
|
||||
|
||||
# if true, uses the go structs for the syft-json format for templating.
|
||||
# if false, uses the syft-json output for templating (which follows the syft JSON schema exactly).
|
||||
#
|
||||
# Note: long term support for this option is not guaranteed (it may change or break at any time).
|
||||
# SYFT_FORMAT_TEMPLATE_LEGACY env var
|
||||
legacy: false
|
||||
|
||||
# all spdx-json format options
|
||||
spdx-json:
|
||||
|
||||
# include space indention and newlines
|
||||
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||
# SYFT_FORMAT_SPDX_JSON_PRETTY env var
|
||||
pretty: false
|
||||
|
||||
# all cyclonedx-json format options
|
||||
cyclonedx-json:
|
||||
|
||||
# include space indention and newlines
|
||||
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||
# SYFT_FORMAT_CYCLONEDX_JSON_PRETTY env var
|
||||
pretty: false
|
||||
|
||||
# all cyclonedx-xml format options
|
||||
cyclonedx-xml:
|
||||
|
||||
# include space indention
|
||||
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||
# SYFT_FORMAT_CYCLONEDX_XML_PRETTY env var
|
||||
pretty: false
|
||||
|
||||
|
||||
file:
|
||||
|
||||
metadata:
|
||||
# select which files should be captured by the file-metadata cataloger and included in the SBOM.
|
||||
# Options include:
|
||||
# - "all": capture all files from the search space
|
||||
# - "owned-by-package": capture only files owned by packages
|
||||
# - "none", "": do not capture any files
|
||||
# SYFT_FILE_METADATA_SELECTION env var
|
||||
selection: "owned-by-package"
|
||||
|
||||
# the file digest algorithms to use when cataloging files (options: "md5", "sha1", "sha224", "sha256", "sha384", "sha512")
|
||||
# SYFT_FILE_METADATA_DIGESTS env var
|
||||
digests:
|
||||
- "sha256"
|
||||
- "sha1"
|
||||
|
||||
# capture the contents of select files in the SBOM
|
||||
content:
|
||||
# skip searching a file entirely if it is above the given size (default = 1MB; unit = bytes)
|
||||
# SYFT_FILE_CONTENT_SKIP_FILES_ABOVE_SIZE env var
|
||||
skip-files-above-size: 1048576
|
||||
|
||||
# file globs for the cataloger to match on
|
||||
# SYFT_FILE_CONTENT_GLOBS env var
|
||||
globs: []
|
||||
|
||||
|
||||
# cataloging packages is exposed through the packages and power-user subcommands
|
||||
package:
|
||||
|
||||
# search within archives that do contain a file index to search against (zip)
|
||||
# note: for now this only applies to the java package cataloger
|
||||
# SYFT_PACKAGE_SEARCH_INDEXED_ARCHIVES env var
|
||||
search-indexed-archives: true
|
||||
|
||||
# search within archives that do not contain a file index to search against (tar, tar.gz, tar.bz2, etc)
|
||||
# note: enabling this may result in a performance impact since all discovered compressed tars will be decompressed
|
||||
# note: for now this only applies to the java package cataloger
|
||||
# SYFT_PACKAGE_SEARCH_UNINDEXED_ARCHIVES env var
|
||||
search-unindexed-archives: false
|
||||
|
||||
# allows users to exclude synthetic binary packages from the sbom
|
||||
# these packages are removed if an overlap with a non-synthetic package is found
|
||||
# SYFT_PACKAGE_EXCLUDE_BINARY_OVERLAP_BY_OWNERSHIP env var
|
||||
exclude-binary-overlap-by-ownership: true
|
||||
|
||||
|
||||
golang:
|
||||
# search for go package licences in the GOPATH of the system running Syft, note that this is outside the
|
||||
# container filesystem and potentially outside the root of a local directory scan
|
||||
# SYFT_GOLANG_SEARCH_LOCAL_MOD_CACHE_LICENSES env var
|
||||
search-local-mod-cache-licenses: false
|
||||
|
||||
# specify an explicit go mod cache directory, if unset this defaults to $GOPATH/pkg/mod or $HOME/go/pkg/mod
|
||||
# SYFT_GOLANG_LOCAL_MOD_CACHE_DIR env var
|
||||
local-mod-cache-dir: ""
|
||||
|
||||
# search for go package licences by retrieving the package from a network proxy
|
||||
# SYFT_GOLANG_SEARCH_REMOTE_LICENSES env var
|
||||
search-remote-licenses: false
|
||||
|
||||
# remote proxy to use when retrieving go packages from the network,
|
||||
# if unset this defaults to $GOPROXY followed by https://proxy.golang.org
|
||||
# SYFT_GOLANG_PROXY env var
|
||||
proxy: ""
|
||||
|
||||
# specifies packages which should not be fetched by proxy
|
||||
# if unset this defaults to $GONOPROXY
|
||||
# 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
|
||||
# enables Syft to use the network to fill in more detailed information about artifacts
|
||||
# currently this enables searching maven-url for license data
|
||||
# when running across pom.xml files that could have more information, syft will
|
||||
# explicitly search maven for license information by querying the online pom when this is true
|
||||
# this option is helpful for when the parent pom has more data,
|
||||
# that is not accessible from within the final built artifact
|
||||
use-network: false
|
||||
|
||||
linux-kernel:
|
||||
# whether to catalog linux kernel modules found within lib/modules/** directories
|
||||
# SYFT_LINUX_KERNEL_CATALOG_MODULES env var
|
||||
catalog-modules: true
|
||||
|
||||
python:
|
||||
# when running across entries in requirements.txt that do not specify a specific version
|
||||
# (e.g. "sqlalchemy >= 1.0.0, <= 2.0.0, != 3.0.0, <= 3.0.0"), attempt to guess what the version could
|
||||
# be based on the version requirements specified (e.g. "1.0.0"). When enabled the lowest expressible version
|
||||
# when given an arbitrary constraint will be used (even if that version may not be available/published).
|
||||
guess-unpinned-requirements: false
|
||||
|
||||
javascript:
|
||||
search-remote-licenses: false
|
||||
npm-base-url: "https://registry.npmjs.org"
|
||||
|
||||
|
||||
# configuration for the source that the SBOM is generated from (e.g. a file, directory, or container image)
|
||||
source:
|
||||
# alias name for the source
|
||||
# SYFT_SOURCE_NAME env var / --source-name flag
|
||||
name: ""
|
||||
|
||||
# alias version for the source
|
||||
# SYFT_SOURCE_VERSION env var / --source-version flag
|
||||
version: ""
|
||||
|
||||
# base directory for scanning, no links will be followed above this directory, and all paths will be
|
||||
# reported relative to this directory
|
||||
# SYFT_SOURCE_BASE_PATH env var
|
||||
base-path: ''
|
||||
|
||||
# options affecting the file source type
|
||||
file:
|
||||
# the file digest algorithms to use on the scanned file (options: "md5", "sha1", "sha224", "sha256", "sha384", "sha512")
|
||||
digests:
|
||||
- "sha256"
|
||||
|
||||
image:
|
||||
|
||||
# allows users to specify which image source should be used to generate the sbom
|
||||
# valid values are: registry, docker, podman
|
||||
# SYFT_SOURCE_IMAGE_DEFAULT_PULL_SOURCE env var
|
||||
default-pull-source: ""
|
||||
|
||||
|
||||
# options when pulling directly from a registry via the "registry:" or "containerd:" scheme
|
||||
registry:
|
||||
# skip TLS verification when communicating with the registry
|
||||
# SYFT_REGISTRY_INSECURE_SKIP_TLS_VERIFY env var
|
||||
insecure-skip-tls-verify: false
|
||||
|
||||
# use http instead of https when connecting to the registry
|
||||
# SYFT_REGISTRY_INSECURE_USE_HTTP env var
|
||||
insecure-use-http: false
|
||||
|
||||
# filepath to a CA certificate (or directory containing *.crt, *.cert, *.pem) used to generate the client certificate
|
||||
# SYFT_REGISTRY_CA_CERT env var
|
||||
ca-cert: ""
|
||||
|
||||
# credentials for specific registries
|
||||
auth:
|
||||
# the URL to the registry (e.g. "docker.io", "localhost:5000", etc.)
|
||||
# SYFT_REGISTRY_AUTH_AUTHORITY env var
|
||||
- authority: ""
|
||||
|
||||
# SYFT_REGISTRY_AUTH_USERNAME env var
|
||||
username: ""
|
||||
|
||||
# SYFT_REGISTRY_AUTH_PASSWORD env var
|
||||
password: ""
|
||||
|
||||
# note: token and username/password are mutually exclusive
|
||||
# SYFT_REGISTRY_AUTH_TOKEN env var
|
||||
token: ""
|
||||
|
||||
# filepath to the client certificate used for TLS authentication to the registry
|
||||
# SYFT_REGISTRY_AUTH_TLS_CERT env var
|
||||
tls-cert: ""
|
||||
|
||||
# filepath to the client key used for TLS authentication to the registry
|
||||
# SYFT_REGISTRY_AUTH_TLS_KEY env var
|
||||
tls-key: ""
|
||||
|
||||
# - ... # note, more credentials can be provided via config file only (not env vars)
|
||||
|
||||
# generate an attested SBOM
|
||||
attest:
|
||||
# path to the private key file to use for attestation
|
||||
# SYFT_ATTEST_KEY env var
|
||||
key: "cosign.key"
|
||||
|
||||
# password to decrypt to given private key
|
||||
# SYFT_ATTEST_PASSWORD env var, additionally responds to COSIGN_PASSWORD
|
||||
password: ""
|
||||
|
||||
log:
|
||||
# use structured logging
|
||||
# SYFT_LOG_STRUCTURED env var
|
||||
structured: false
|
||||
|
||||
# the log level; note: detailed logging suppress the ETUI
|
||||
# SYFT_LOG_LEVEL env var
|
||||
level: "error"
|
||||
|
||||
# location to write the log file (default is not to have a log file)
|
||||
# SYFT_LOG_FILE env var
|
||||
file: ""
|
||||
```
|
||||
|
||||
### Adding an SBOM to an image as an attestation using Syft
|
||||
|
||||
`syft attest --output [FORMAT] --key [KEY] [SOURCE] [flags]`
|
||||
|
||||
SBOMs themselves can serve as input to different analysis tools. [Grype](https://github.com/anchore/grype), a vulnerability scanner CLI tool from Anchore, is one such tool. Publishers of container images can use attestations to enable their consumers to trust Syft-generated SBOM descriptions of those container images. To create and provide these attestations, image publishers can run `syft attest` in conjunction with the [cosign](https://github.com/sigstore/cosign) tool to attach SBOM attestations to their images.
|
||||
|
||||
#### Example attestation
|
||||
Note for the following example replace `docker.io/image:latest` with an image you own. You should also have push access to
|
||||
its remote reference. Replace `$MY_PRIVATE_KEY` with a private key you own or have generated with cosign.
|
||||
|
||||
```bash
|
||||
syft attest --key $MY_PRIVATE_KEY -o spdx-json docker.io/image:latest > image_latest_sbom_attestation.json
|
||||
cosign attach attestation --attestation image_latest_sbom_attestation.json docker.io/image:latest
|
||||
```
|
||||
|
||||
Verify the new attestation exists on your image.
|
||||
|
||||
```bash
|
||||
cosign verify-attestation --key $MY_PUBLIC_KEY --type spdxjson docker.io/image:latest | jq '.payload | @base64d | .payload | fromjson | .predicate'
|
||||
```
|
||||
|
||||
You should see this output along with the attached SBOM:
|
||||
|
||||
```
|
||||
Verification for docker.io/image:latest --
|
||||
The following checks were performed on each of these signatures:
|
||||
- The cosign claims were validated
|
||||
- The signatures were verified against the specified public key
|
||||
- Any certificates were verified against the Fulcio roots.
|
||||
```
|
||||
|
||||
Consumers of your image can now trust that the SBOM associated with your image is correct and from a trusted source.
|
||||
|
||||
The SBOM can be piped to Grype:
|
||||
|
||||
|
||||
```bash
|
||||
cosign verify-attestation --key $MY_PUBLIC_KEY --type spdxjson docker.io/image:latest | jq '.payload | @base64d | .payload | fromjson | .predicate' | grype
|
||||
```
|
||||
|
||||
@@ -470,16 +470,6 @@ tasks:
|
||||
silent: true
|
||||
- "{{ .RELEASE_CMD }}"
|
||||
|
||||
ci-release-version-file:
|
||||
# desc: "[CI only] Update the version file"
|
||||
deps: [tools]
|
||||
cmds:
|
||||
- task: ci-check
|
||||
- ".github/scripts/update-version-file.sh {{ .RELEASE_VERSION }}"
|
||||
requires:
|
||||
vars:
|
||||
- RELEASE_VERSION
|
||||
|
||||
|
||||
## Cleanup targets #################################
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ func create(id clio.Identification, out io.Writer) (clio.Application, *cobra.Com
|
||||
commands.Attest(app),
|
||||
commands.Convert(app),
|
||||
clio.VersionCommand(id),
|
||||
clio.ConfigCommand(app, nil),
|
||||
cranecmd.NewCmdAuthLogin(id.Name), // syft login uses the same command as crane
|
||||
)
|
||||
|
||||
|
||||
@@ -12,16 +12,8 @@ type Attest struct {
|
||||
Password secret `yaml:"password" json:"password" mapstructure:"password"`
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.FlagAdder
|
||||
clio.FieldDescriber
|
||||
} = (*Attest)(nil)
|
||||
var _ clio.FlagAdder = (*Attest)(nil)
|
||||
|
||||
func (o *Attest) AddFlags(flags clio.FlagSet) {
|
||||
flags.StringVarP((*string)(&o.Key), "key", "k", "the key to use for the attestation")
|
||||
}
|
||||
|
||||
func (o *Attest) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.Password, `password to decrypt to given private key
|
||||
additionally responds to COSIGN_PASSWORD env var`)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/clio"
|
||||
intFile "github.com/anchore/syft/internal/file"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
@@ -46,11 +45,6 @@ func defaultFileConfig() fileConfig {
|
||||
}
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.PostLoader
|
||||
clio.FieldDescriber
|
||||
} = (*fileConfig)(nil)
|
||||
|
||||
func (c *fileConfig) PostLoad() error {
|
||||
digests := strset.New(c.Metadata.Digests...).List()
|
||||
sort.Strings(digests)
|
||||
@@ -62,17 +56,3 @@ func (c *fileConfig) PostLoad() error {
|
||||
}
|
||||
return fmt.Errorf("invalid file metadata selection: %q", c.Metadata.Selection)
|
||||
}
|
||||
|
||||
func (c *fileConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&c.Metadata.Selection, `select which files should be captured by the file-metadata cataloger and included in the SBOM.
|
||||
Options include:
|
||||
- "all": capture all files from the search space
|
||||
- "owned-by-package": capture only files owned by packages
|
||||
- "none", "": do not capture any files`)
|
||||
descriptions.Add(&c.Metadata.Digests, `the file digest algorithms to use when cataloging files (options: "md5", "sha1", "sha224", "sha256", "sha384", "sha512")`)
|
||||
|
||||
descriptions.Add(&c.Content.SkipFilesAboveSize, `skip searching a file entirely if it is above the given size (default = 1MB; unit = bytes)`)
|
||||
descriptions.Add(&c.Content.Globs, `file globs for the cataloger to match on`)
|
||||
|
||||
descriptions.Add(&c.Executable.Globs, `file globs for the cataloger to match on`)
|
||||
}
|
||||
|
||||
@@ -7,19 +7,16 @@ import (
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
var _ interface {
|
||||
clio.PostLoader
|
||||
clio.FieldDescriber
|
||||
} = (*Format)(nil)
|
||||
var _ clio.PostLoader = (*Format)(nil)
|
||||
|
||||
// Format contains all user configuration for output formatting.
|
||||
type Format struct {
|
||||
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||
Template FormatTemplate `yaml:"template" json:"template" mapstructure:"template" description:"all template format options"`
|
||||
SyftJSON FormatSyftJSON `yaml:"json" json:"json" mapstructure:"json" description:"all syft-json format options"`
|
||||
SPDXJSON FormatSPDXJSON `yaml:"spdx-json" json:"spdx-json" mapstructure:"spdx-json" description:"all spdx-json format options"`
|
||||
CyclonedxJSON FormatCyclonedxJSON `yaml:"cyclonedx-json" json:"cyclonedx-json" mapstructure:"cyclonedx-json" description:"all cyclonedx-json format options"`
|
||||
CyclonedxXML FormatCyclonedxXML `yaml:"cyclonedx-xml" json:"cyclonedx-xml" mapstructure:"cyclonedx-xml" description:"all cyclonedx-xml format options"`
|
||||
Template FormatTemplate `yaml:"template" json:"template" mapstructure:"template"`
|
||||
SyftJSON FormatSyftJSON `yaml:"json" json:"json" mapstructure:"json"`
|
||||
SPDXJSON FormatSPDXJSON `yaml:"spdx-json" json:"spdx-json" mapstructure:"spdx-json"`
|
||||
CyclonedxJSON FormatCyclonedxJSON `yaml:"cyclonedx-json" json:"cyclonedx-json" mapstructure:"cyclonedx-json"`
|
||||
CyclonedxXML FormatCyclonedxXML `yaml:"cyclonedx-xml" json:"cyclonedx-xml" mapstructure:"cyclonedx-xml"`
|
||||
}
|
||||
|
||||
func (o *Format) PostLoad() error {
|
||||
@@ -31,33 +28,6 @@ func (o *Format) PostLoad() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Format) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.Pretty, `default value for all formats that support the "pretty" option (default is unset)`)
|
||||
descriptions.Add(&o.SyftJSON, `all syft-json format options`)
|
||||
descriptions.Add(&o.SyftJSON.Legacy, `transform any syft-json output to conform to an approximation of the v11.0.1 schema. This includes:
|
||||
- using the package metadata type names from before v12 of the JSON schema (changed in https://github.com/anchore/syft/pull/1983)
|
||||
|
||||
Note: this will still include package types and fields that were added at or after json schema v12. This means
|
||||
that output might not strictly be json schema v11 compliant, however, for consumers that require time to port
|
||||
over to the final syft 1.0 json output this option can be used to ease the transition.
|
||||
|
||||
Note: long term support for this option is not guaranteed (it may change or break at any time)`)
|
||||
|
||||
descriptions.Add(&o.Template.Path, `path to the template file to use when rendering the output with the template output format.
|
||||
Note that all template paths are based on the current syft-json schema`)
|
||||
descriptions.Add(&o.Template.Legacy, `if true, uses the go structs for the syft-json format for templating.
|
||||
if false, uses the syft-json output for templating (which follows the syft JSON schema exactly).
|
||||
|
||||
Note: long term support for this option is not guaranteed (it may change or break at any time)`)
|
||||
|
||||
prettyDescription := `include space indention and newlines
|
||||
note: inherits default value from 'format.pretty' or 'false' if parent is unset`
|
||||
descriptions.Add(&o.SyftJSON.Pretty, prettyDescription)
|
||||
descriptions.Add(&o.SPDXJSON.Pretty, prettyDescription)
|
||||
descriptions.Add(&o.CyclonedxJSON.Pretty, prettyDescription)
|
||||
descriptions.Add(&o.CyclonedxXML.Pretty, prettyDescription)
|
||||
}
|
||||
|
||||
func DefaultFormat() Format {
|
||||
return Format{
|
||||
Template: DefaultFormatTemplate(),
|
||||
|
||||
@@ -3,7 +3,6 @@ package options
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/clio"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/golang"
|
||||
)
|
||||
|
||||
@@ -16,28 +15,6 @@ type golangConfig struct {
|
||||
MainModuleVersion golangMainModuleVersionConfig `json:"main-module-version" yaml:"main-module-version" mapstructure:"main-module-version"`
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.FieldDescriber
|
||||
} = (*golangConfig)(nil)
|
||||
|
||||
func (o *golangConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.SearchLocalModCacheLicenses, `search for go package licences in the GOPATH of the system running Syft, note that this is outside the
|
||||
container filesystem and potentially outside the root of a local directory scan`)
|
||||
descriptions.Add(&o.LocalModCacheDir, `specify an explicit go mod cache directory, if unset this defaults to $GOPATH/pkg/mod or $HOME/go/pkg/mod`)
|
||||
descriptions.Add(&o.SearchRemoteLicenses, `search for go package licences by retrieving the package from a network proxy`)
|
||||
descriptions.Add(&o.Proxy, `remote proxy to use when retrieving go packages from the network,
|
||||
if unset this defaults to $GOPROXY followed by https://proxy.golang.org`)
|
||||
descriptions.Add(&o.NoProxy, `specifies packages which should not be fetched by proxy
|
||||
if unset this defaults to $GONOPROXY`)
|
||||
descriptions.Add(&o.MainModuleVersion, `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.`)
|
||||
descriptions.Add(&o.MainModuleVersion.FromLDFlags, `look for LD flags that appear to be setting a version (e.g. -X main.version=1.0.0)`)
|
||||
descriptions.Add(&o.MainModuleVersion.FromBuildSettings, `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`)
|
||||
descriptions.Add(&o.MainModuleVersion.FromContents, `search for semver-like strings in the binary contents`)
|
||||
}
|
||||
|
||||
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"`
|
||||
|
||||
@@ -1,24 +1,7 @@
|
||||
package options
|
||||
|
||||
import "github.com/anchore/clio"
|
||||
|
||||
type javaConfig struct {
|
||||
UseNetwork bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"`
|
||||
MavenURL string `yaml:"maven-url" json:"maven-url" mapstructure:"maven-url"`
|
||||
MaxParentRecursiveDepth int `yaml:"max-parent-recursive-depth" json:"max-parent-recursive-depth" mapstructure:"max-parent-recursive-depth"`
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.FieldDescriber
|
||||
} = (*javaConfig)(nil)
|
||||
|
||||
func (o *javaConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.UseNetwork, `enables Syft to use the network to fill in more detailed information about artifacts
|
||||
currently this enables searching maven-url for license data
|
||||
when running across pom.xml files that could have more information, syft will
|
||||
explicitly search maven for license information by querying the online pom when this is true
|
||||
this option is helpful for when the parent pom has more data,
|
||||
that is not accessible from within the final built artifact`)
|
||||
descriptions.Add(&o.MavenURL, `maven repository to use, defaults to Maven central`)
|
||||
descriptions.Add(&o.MaxParentRecursiveDepth, `depth to recursively resolve parent POMs`)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
package options
|
||||
|
||||
import "github.com/anchore/clio"
|
||||
|
||||
type javaScriptConfig struct {
|
||||
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
|
||||
NpmBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.FieldDescriber
|
||||
} = (*javaScriptConfig)(nil)
|
||||
|
||||
func (o *javaScriptConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.SearchRemoteLicenses, `enables Syft to use the network to fill in more detailed license information`)
|
||||
descriptions.Add(&o.NpmBaseURL, `base NPM url to use`)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package options
|
||||
|
||||
import "github.com/anchore/clio"
|
||||
|
||||
type linuxKernelConfig struct {
|
||||
CatalogModules bool `json:"catalog-modules" yaml:"catalog-modules" mapstructure:"catalog-modules"`
|
||||
}
|
||||
@@ -11,11 +9,3 @@ func defaultLinuxKernelConfig() linuxKernelConfig {
|
||||
CatalogModules: true,
|
||||
}
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.FieldDescriber
|
||||
} = (*linuxKernelConfig)(nil)
|
||||
|
||||
func (o *linuxKernelConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.CatalogModules, `whether to catalog linux kernel modules found within lib/modules/** directories`)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
var _ interface {
|
||||
clio.FlagAdder
|
||||
clio.PostLoader
|
||||
clio.FieldDescriber
|
||||
} = (*Output)(nil)
|
||||
|
||||
// Output has the standard output options syft accepts: multiple -o, --file, --template
|
||||
@@ -71,15 +70,6 @@ func (o *Output) AddFlags(flags clio.FlagSet) {
|
||||
fmt.Sprintf("report output format (<format>=<file> to output to a file), formats=%v", names))
|
||||
}
|
||||
|
||||
func (o *Output) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.Outputs, `the output format(s) of the SBOM report (options: syft-table, syft-text, syft-json, spdx-json, ...)
|
||||
to specify multiple output files in differing formats, use a list:
|
||||
output:
|
||||
- "syft-json=<syft-json-output-file>"
|
||||
- "spdx-json=<spdx-json-output-file>"
|
||||
`)
|
||||
}
|
||||
|
||||
func (o Output) SBOMWriter() (sbom.Writer, error) {
|
||||
names := o.OutputNameSet()
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"github.com/anchore/clio"
|
||||
"github.com/anchore/syft/syft/cataloging"
|
||||
)
|
||||
import "github.com/anchore/syft/syft/cataloging"
|
||||
|
||||
type packageConfig struct {
|
||||
SearchUnindexedArchives bool `yaml:"search-unindexed-archives" json:"search-unindexed-archives" mapstructure:"search-unindexed-archives"`
|
||||
@@ -11,20 +8,6 @@ type packageConfig struct {
|
||||
ExcludeBinaryOverlapByOwnership bool `yaml:"exclude-binary-overlap-by-ownership" json:"exclude-binary-overlap-by-ownership" mapstructure:"exclude-binary-overlap-by-ownership"` // exclude synthetic binary packages owned by os package files
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.FieldDescriber
|
||||
} = (*packageConfig)(nil)
|
||||
|
||||
func (o *packageConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.SearchUnindexedArchives, `search within archives that do contain a file index to search against (zip)
|
||||
note: for now this only applies to the java package cataloger`)
|
||||
descriptions.Add(&o.SearchIndexedArchives, `search within archives that do not contain a file index to search against (tar, tar.gz, tar.bz2, etc)
|
||||
note: enabling this may result in a performance impact since all discovered compressed tars will be decompressed
|
||||
note: for now this only applies to the java package cataloger`)
|
||||
descriptions.Add(&o.ExcludeBinaryOverlapByOwnership, `allows users to exclude synthetic binary packages from the sbom
|
||||
these packages are removed if an overlap with a non-synthetic package is found`)
|
||||
}
|
||||
|
||||
func defaultPackageConfig() packageConfig {
|
||||
c := cataloging.DefaultArchiveSearchConfig()
|
||||
return packageConfig{
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
package options
|
||||
|
||||
import "github.com/anchore/clio"
|
||||
|
||||
type pythonConfig struct {
|
||||
GuessUnpinnedRequirements bool `json:"guess-unpinned-requirements" yaml:"guess-unpinned-requirements" mapstructure:"guess-unpinned-requirements"`
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.FieldDescriber
|
||||
} = (*pythonConfig)(nil)
|
||||
|
||||
func (o *pythonConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.GuessUnpinnedRequirements, `when running across entries in requirements.txt that do not specify a specific version
|
||||
(e.g. "sqlalchemy >= 1.0.0, <= 2.0.0, != 3.0.0, <= 3.0.0"), attempt to guess what the version could
|
||||
be based on the version requirements specified (e.g. "1.0.0"). When enabled the lowest expressible version
|
||||
when given an arbitrary constraint will be used (even if that version may not be available/published).`)
|
||||
}
|
||||
|
||||
@@ -25,10 +25,7 @@ type registryConfig struct {
|
||||
CACert string `yaml:"ca-cert" json:"ca-cert" mapstructure:"ca-cert"`
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.PostLoader
|
||||
clio.FieldDescriber
|
||||
} = (*registryConfig)(nil)
|
||||
var _ clio.PostLoader = (*registryConfig)(nil)
|
||||
|
||||
func (cfg *registryConfig) PostLoad() error {
|
||||
// there may be additional credentials provided by env var that should be appended to the set of credentials
|
||||
@@ -58,20 +55,6 @@ func (cfg *registryConfig) PostLoad() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *registryConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&cfg.InsecureSkipTLSVerify, "skip TLS verification when communicating with the registry")
|
||||
descriptions.Add(&cfg.InsecureUseHTTP, "use http instead of https when connecting to the registry")
|
||||
descriptions.Add(&cfg.CACert, "filepath to a CA certificate (or directory containing *.crt, *.cert, *.pem) used to generate the client certificate")
|
||||
descriptions.Add(&cfg.Auth, `Authentication credentials for specific registries. Each entry describes authentication for a specific authority:
|
||||
- authority: the registry authority URL the URL to the registry (e.g. "docker.io", "localhost:5000", etc.) (env: SYFT_REGISTRY_AUTH_AUTHORITY)
|
||||
username: a username if using basic credentials (env: SYFT_REGISTRY_AUTH_USERNAME)
|
||||
password: a corresponding password (env: SYFT_REGISTRY_AUTH_PASSWORD)
|
||||
token: a token if using token-based authentication, mutually exclusive with username/password (env: SYFT_REGISTRY_AUTH_TOKEN)
|
||||
tls-cert: filepath to the client certificate used for TLS authentication to the registry (env: SYFT_REGISTRY_AUTH_TLS_CERT)
|
||||
tls-key: filepath to the client key used for TLS authentication to the registry (env: SYFT_REGISTRY_AUTH_TLS_KEY)
|
||||
`)
|
||||
}
|
||||
|
||||
func hasNonEmptyCredentials(username, password, token, tlsCert, tlsKey string) bool {
|
||||
hasUserPass := username != "" && password != ""
|
||||
hasToken := token != ""
|
||||
|
||||
@@ -17,6 +17,6 @@ func defaultRelationshipsConfig() relationshipsConfig {
|
||||
}
|
||||
|
||||
func (r *relationshipsConfig) DescribeFields(descriptions fangs.FieldDescriptionSet) {
|
||||
descriptions.Add(&r.PackageFileOwnership, "include package-to-file relationships that indicate which files are owned by which packages")
|
||||
descriptions.Add(&r.PackageFileOwnershipOverlap, "include package-to-package relationships that indicate one package is owned by another due to files claimed to be owned by one package are also evidence of another package's existence")
|
||||
descriptions.Add(&r.PackageFileOwnership, "include package-to-file relationships that indicate which files are owned by which packages.")
|
||||
descriptions.Add(&r.PackageFileOwnershipOverlap, "include package-to-package relationships that indicate one package is owned by another due to files claimed to be owned by one package are also evidence of another package's existence.")
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/clio"
|
||||
"github.com/anchore/syft/syft/source/sourceproviders"
|
||||
)
|
||||
|
||||
@@ -23,16 +22,6 @@ type fileSource struct {
|
||||
Digests []string `json:"digests" yaml:"digests" mapstructure:"digests"`
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
clio.FieldDescriber
|
||||
} = (*sourceConfig)(nil)
|
||||
|
||||
func (o *sourceConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.File.Digests, `the file digest algorithms to use on the scanned file (options: "md5", "sha1", "sha224", "sha256", "sha384", "sha512")`)
|
||||
descriptions.Add(&o.Image.DefaultPullSource, `allows users to specify which image source should be used to generate the sbom
|
||||
valid values are: registry, docker, podman`)
|
||||
}
|
||||
|
||||
type imageSource struct {
|
||||
DefaultPullSource string `json:"default-pull-source" yaml:"default-pull-source" mapstructure:"default-pull-source"`
|
||||
}
|
||||
|
||||
@@ -468,12 +468,4 @@ var commonTestCases = []testCase{
|
||||
"memcached": "3.2.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find lua rock package",
|
||||
pkgType: pkg.LuaRocksPkg,
|
||||
pkgLanguage: pkg.Lua,
|
||||
pkgInfo: map[string]string{
|
||||
"kong": "3.7.0-0",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func TestBinaryElfRelationships(t *testing.T) {
|
||||
// node --> ["dependency of" nodes]
|
||||
expectedGraph := map[string][]string{
|
||||
"glibc": {
|
||||
"libhello_world.so",
|
||||
"syfttestfixture",
|
||||
},
|
||||
"libstdc++": {
|
||||
"syfttestfixture",
|
||||
},
|
||||
"libhello_world.so": {
|
||||
"syfttestfixture",
|
||||
},
|
||||
}
|
||||
|
||||
// run the test...
|
||||
sbom, _ := catalogFixtureImage(t, "elf-test-fixtures", source.SquashedScope)
|
||||
|
||||
// get a mapping of package names to their IDs
|
||||
nameToId := map[string]artifact.ID{}
|
||||
|
||||
recordPkgId := func(name string) {
|
||||
pkgs := sbom.Artifacts.Packages.PackagesByName(name)
|
||||
require.NotEmpty(t, pkgs, "expected package %q to be present in the SBOM", name)
|
||||
for _, p := range pkgs {
|
||||
nameToId[p.Name] = p.ID()
|
||||
}
|
||||
}
|
||||
for name, depNames := range expectedGraph {
|
||||
recordPkgId(name)
|
||||
for _, depName := range depNames {
|
||||
recordPkgId(depName)
|
||||
}
|
||||
}
|
||||
|
||||
for name, expectedDepNames := range expectedGraph {
|
||||
pkgId := nameToId[name]
|
||||
p := sbom.Artifacts.Packages.Package(pkgId)
|
||||
require.NotNil(t, p, "expected package %q to be present in the SBOM", name)
|
||||
|
||||
rels := sbom.RelationshipsForPackage(*p, artifact.DependencyOfRelationship)
|
||||
require.NotEmpty(t, rels, "expected package %q to have relationships", name)
|
||||
|
||||
toIds := map[artifact.ID]struct{}{}
|
||||
for _, rel := range rels {
|
||||
toIds[rel.To.ID()] = struct{}{}
|
||||
}
|
||||
|
||||
for _, depName := range expectedDepNames {
|
||||
depId := nameToId[depName]
|
||||
_, exists := toIds[depId]
|
||||
require.True(t, exists, "expected package %q to have a relationship to %q", name, depName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
../../../../../../syft/pkg/cataloger/binary/test-fixtures/elf-test-fixtures
|
||||
-612
@@ -1,612 +0,0 @@
|
||||
package = "kong"
|
||||
version = "3.7.0-0"
|
||||
rockspec_format = "3.0"
|
||||
supported_platforms = {"linux", "macosx"}
|
||||
source = {
|
||||
url = "git+https://github.com/Kong/kong.git",
|
||||
tag = "3.7.0"
|
||||
}
|
||||
description = {
|
||||
summary = "Kong is a scalable and customizable API Management Layer built on top of Nginx.",
|
||||
homepage = "https://konghq.com",
|
||||
license = "Apache 2.0"
|
||||
}
|
||||
dependencies = {
|
||||
"inspect == 3.1.3",
|
||||
"luasec == 1.3.2",
|
||||
"luasocket == 3.0-rc1",
|
||||
"penlight == 1.13.1",
|
||||
"lua-resty-http == 0.17.1",
|
||||
"lua-resty-jit-uuid == 0.0.7",
|
||||
"lua-ffi-zlib == 0.6",
|
||||
"multipart == 0.5.9",
|
||||
"version == 1.0.1",
|
||||
"kong-lapis == 1.16.0.1",
|
||||
"kong-pgmoon == 1.16.2",
|
||||
"luatz == 0.4",
|
||||
"lua_system_constants == 0.1.4",
|
||||
"lyaml == 6.2.8",
|
||||
"luasyslog == 2.0.1",
|
||||
"lua_pack == 2.0.0",
|
||||
"binaryheap >= 0.4",
|
||||
"luaxxhash >= 1.0",
|
||||
"lua-protobuf == 0.5.0",
|
||||
"lua-resty-healthcheck == 3.0.1",
|
||||
"lua-messagepack == 0.5.4",
|
||||
"lua-resty-aws == 1.3.6",
|
||||
"lua-resty-openssl == 1.2.0",
|
||||
"lua-resty-counter == 0.2.1",
|
||||
"lua-resty-ipmatcher == 0.6.1",
|
||||
"lua-resty-acme == 0.12.0",
|
||||
"lua-resty-session == 4.0.5",
|
||||
"lua-resty-timer-ng == 0.2.6",
|
||||
"lpeg == 1.1.0",
|
||||
"lua-resty-ljsonschema == 1.1.6-2",
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
["kong"] = "kong/init.lua",
|
||||
["kong.meta"] = "kong/meta.lua",
|
||||
["kong.cache"] = "kong/cache/init.lua",
|
||||
["kong.cache.warmup"] = "kong/cache/warmup.lua",
|
||||
["kong.global"] = "kong/global.lua",
|
||||
["kong.reports"] = "kong/reports.lua",
|
||||
["kong.constants"] = "kong/constants.lua",
|
||||
["kong.concurrency"] = "kong/concurrency.lua",
|
||||
["kong.deprecation"] = "kong/deprecation.lua",
|
||||
["kong.globalpatches"] = "kong/globalpatches.lua",
|
||||
["kong.error_handlers"] = "kong/error_handlers.lua",
|
||||
["kong.hooks"] = "kong/hooks.lua",
|
||||
|
||||
["kong.router"] = "kong/router/init.lua",
|
||||
["kong.router.traditional"] = "kong/router/traditional.lua",
|
||||
["kong.router.compat"] = "kong/router/compat.lua",
|
||||
["kong.router.expressions"] = "kong/router/expressions.lua",
|
||||
["kong.router.atc"] = "kong/router/atc.lua",
|
||||
["kong.router.fields"] = "kong/router/fields.lua",
|
||||
["kong.router.utils"] = "kong/router/utils.lua",
|
||||
|
||||
["kong.conf_loader"] = "kong/conf_loader/init.lua",
|
||||
["kong.conf_loader.constants"] = "kong/conf_loader/constants.lua",
|
||||
["kong.conf_loader.parse"] = "kong/conf_loader/parse.lua",
|
||||
["kong.conf_loader.listeners"] = "kong/conf_loader/listeners.lua",
|
||||
|
||||
["kong.clustering"] = "kong/clustering/init.lua",
|
||||
["kong.clustering.data_plane"] = "kong/clustering/data_plane.lua",
|
||||
["kong.clustering.control_plane"] = "kong/clustering/control_plane.lua",
|
||||
["kong.clustering.utils"] = "kong/clustering/utils.lua",
|
||||
["kong.clustering.events"] = "kong/clustering/events.lua",
|
||||
["kong.clustering.compat"] = "kong/clustering/compat/init.lua",
|
||||
["kong.clustering.compat.version"] = "kong/clustering/compat/version.lua",
|
||||
["kong.clustering.compat.removed_fields"] = "kong/clustering/compat/removed_fields.lua",
|
||||
["kong.clustering.compat.checkers"] = "kong/clustering/compat/checkers.lua",
|
||||
["kong.clustering.config_helper"] = "kong/clustering/config_helper.lua",
|
||||
["kong.clustering.tls"] = "kong/clustering/tls.lua",
|
||||
|
||||
["kong.cluster_events"] = "kong/cluster_events/init.lua",
|
||||
["kong.cluster_events.strategies.postgres"] = "kong/cluster_events/strategies/postgres.lua",
|
||||
["kong.cluster_events.strategies.off"] = "kong/cluster_events/strategies/off.lua",
|
||||
|
||||
["kong.templates.nginx"] = "kong/templates/nginx.lua",
|
||||
["kong.templates.nginx_kong"] = "kong/templates/nginx_kong.lua",
|
||||
["kong.templates.nginx_kong_gui_include"] = "kong/templates/nginx_kong_gui_include.lua",
|
||||
["kong.templates.nginx_kong_stream"] = "kong/templates/nginx_kong_stream.lua",
|
||||
["kong.templates.kong_defaults"] = "kong/templates/kong_defaults.lua",
|
||||
["kong.templates.nginx_inject"] = "kong/templates/nginx_inject.lua",
|
||||
["kong.templates.nginx_kong_inject"] = "kong/templates/nginx_kong_inject.lua",
|
||||
["kong.templates.nginx_kong_stream_inject"] = "kong/templates/nginx_kong_stream_inject.lua",
|
||||
["kong.templates.kong_yml"] = "kong/templates/kong_yml.lua",
|
||||
|
||||
["kong.resty.dns.client"] = "kong/resty/dns/client.lua",
|
||||
["kong.resty.dns.utils"] = "kong/resty/dns/utils.lua",
|
||||
["kong.resty.ctx"] = "kong/resty/ctx.lua",
|
||||
|
||||
["kong.resty.mlcache"] = "kong/resty/mlcache/init.lua",
|
||||
["kong.resty.mlcache.ipc"] = "kong/resty/mlcache/ipc.lua",
|
||||
|
||||
["kong.cmd"] = "kong/cmd/init.lua",
|
||||
["kong.cmd.roar"] = "kong/cmd/roar.lua",
|
||||
["kong.cmd.stop"] = "kong/cmd/stop.lua",
|
||||
["kong.cmd.quit"] = "kong/cmd/quit.lua",
|
||||
["kong.cmd.start"] = "kong/cmd/start.lua",
|
||||
["kong.cmd.check"] = "kong/cmd/check.lua",
|
||||
["kong.cmd.config"] = "kong/cmd/config.lua",
|
||||
["kong.cmd.reload"] = "kong/cmd/reload.lua",
|
||||
["kong.cmd.restart"] = "kong/cmd/restart.lua",
|
||||
["kong.cmd.prepare"] = "kong/cmd/prepare.lua",
|
||||
["kong.cmd.migrations"] = "kong/cmd/migrations.lua",
|
||||
["kong.cmd.health"] = "kong/cmd/health.lua",
|
||||
["kong.cmd.vault"] = "kong/cmd/vault.lua",
|
||||
["kong.cmd.version"] = "kong/cmd/version.lua",
|
||||
["kong.cmd.hybrid"] = "kong/cmd/hybrid.lua",
|
||||
["kong.cmd.utils.log"] = "kong/cmd/utils/log.lua",
|
||||
["kong.cmd.utils.kill"] = "kong/cmd/utils/kill.lua",
|
||||
["kong.cmd.utils.env"] = "kong/cmd/utils/env.lua",
|
||||
["kong.cmd.utils.migrations"] = "kong/cmd/utils/migrations.lua",
|
||||
["kong.cmd.utils.tty"] = "kong/cmd/utils/tty.lua",
|
||||
["kong.cmd.utils.nginx_signals"] = "kong/cmd/utils/nginx_signals.lua",
|
||||
["kong.cmd.utils.prefix_handler"] = "kong/cmd/utils/prefix_handler.lua",
|
||||
["kong.cmd.utils.process_secrets"] = "kong/cmd/utils/process_secrets.lua",
|
||||
["kong.cmd.utils.inject_confs"] = "kong/cmd/utils/inject_confs.lua",
|
||||
|
||||
["kong.api"] = "kong/api/init.lua",
|
||||
["kong.api.api_helpers"] = "kong/api/api_helpers.lua",
|
||||
["kong.api.arguments"] = "kong/api/arguments.lua",
|
||||
["kong.api.endpoints"] = "kong/api/endpoints.lua",
|
||||
["kong.api.routes.cache"] = "kong/api/routes/cache.lua",
|
||||
["kong.api.routes.certificates"] = "kong/api/routes/certificates.lua",
|
||||
["kong.api.routes.clustering"] = "kong/api/routes/clustering.lua",
|
||||
["kong.api.routes.config"] = "kong/api/routes/config.lua",
|
||||
["kong.api.routes.consumers"] = "kong/api/routes/consumers.lua",
|
||||
["kong.api.routes.debug"] = "kong/api/routes/debug.lua",
|
||||
["kong.api.routes.filter_chains"] = "kong/api/routes/filter_chains.lua",
|
||||
["kong.api.routes.health"] = "kong/api/routes/health.lua",
|
||||
["kong.api.routes.kong"] = "kong/api/routes/kong.lua",
|
||||
["kong.api.routes.plugins"] = "kong/api/routes/plugins.lua",
|
||||
["kong.api.routes.snis"] = "kong/api/routes/snis.lua",
|
||||
["kong.api.routes.tags"] = "kong/api/routes/tags.lua",
|
||||
["kong.api.routes.targets"] = "kong/api/routes/targets.lua",
|
||||
["kong.api.routes.upstreams"] = "kong/api/routes/upstreams.lua",
|
||||
|
||||
["kong.admin_gui"] = "kong/admin_gui/init.lua",
|
||||
["kong.admin_gui.utils"] = "kong/admin_gui/utils.lua",
|
||||
|
||||
["kong.status"] = "kong/status/init.lua",
|
||||
["kong.status.ready"] = "kong/status/ready.lua",
|
||||
|
||||
["kong.tools.dns"] = "kong/tools/dns.lua",
|
||||
["kong.tools.grpc"] = "kong/tools/grpc.lua",
|
||||
["kong.tools.utils"] = "kong/tools/utils.lua",
|
||||
["kong.tools.timestamp"] = "kong/tools/timestamp.lua",
|
||||
["kong.tools.stream_api"] = "kong/tools/stream_api.lua",
|
||||
["kong.tools.queue"] = "kong/tools/queue.lua",
|
||||
["kong.tools.queue_schema"] = "kong/tools/queue_schema.lua",
|
||||
["kong.tools.sandbox"] = "kong/tools/sandbox.lua",
|
||||
["kong.tools.uri"] = "kong/tools/uri.lua",
|
||||
["kong.tools.kong-lua-sandbox"] = "kong/tools/kong-lua-sandbox.lua",
|
||||
["kong.tools.protobuf"] = "kong/tools/protobuf.lua",
|
||||
["kong.tools.mime_type"] = "kong/tools/mime_type.lua",
|
||||
["kong.tools.request_aware_table"] = "kong/tools/request_aware_table.lua",
|
||||
["kong.tools.gzip"] = "kong/tools/gzip.lua",
|
||||
["kong.tools.string"] = "kong/tools/string.lua",
|
||||
["kong.tools.table"] = "kong/tools/table.lua",
|
||||
["kong.tools.sha256"] = "kong/tools/sha256.lua",
|
||||
["kong.tools.yield"] = "kong/tools/yield.lua",
|
||||
["kong.tools.uuid"] = "kong/tools/uuid.lua",
|
||||
["kong.tools.rand"] = "kong/tools/rand.lua",
|
||||
["kong.tools.system"] = "kong/tools/system.lua",
|
||||
["kong.tools.time"] = "kong/tools/time.lua",
|
||||
["kong.tools.module"] = "kong/tools/module.lua",
|
||||
["kong.tools.ip"] = "kong/tools/ip.lua",
|
||||
["kong.tools.http"] = "kong/tools/http.lua",
|
||||
["kong.tools.cjson"] = "kong/tools/cjson.lua",
|
||||
["kong.tools.redis.schema"] = "kong/tools/redis/schema.lua",
|
||||
|
||||
["kong.runloop.handler"] = "kong/runloop/handler.lua",
|
||||
["kong.runloop.events"] = "kong/runloop/events.lua",
|
||||
["kong.runloop.log_level"] = "kong/runloop/log_level.lua",
|
||||
["kong.runloop.certificate"] = "kong/runloop/certificate.lua",
|
||||
["kong.runloop.plugins_iterator"] = "kong/runloop/plugins_iterator.lua",
|
||||
["kong.runloop.upstream_ssl"] = "kong/runloop/upstream_ssl.lua",
|
||||
["kong.runloop.balancer"] = "kong/runloop/balancer/init.lua",
|
||||
["kong.runloop.balancer.balancers"] = "kong/runloop/balancer/balancers.lua",
|
||||
["kong.runloop.balancer.consistent_hashing"] = "kong/runloop/balancer/consistent_hashing.lua",
|
||||
["kong.runloop.balancer.healthcheckers"] = "kong/runloop/balancer/healthcheckers.lua",
|
||||
["kong.runloop.balancer.least_connections"] = "kong/runloop/balancer/least_connections.lua",
|
||||
["kong.runloop.balancer.latency"] = "kong/runloop/balancer/latency.lua",
|
||||
["kong.runloop.balancer.round_robin"] = "kong/runloop/balancer/round_robin.lua",
|
||||
["kong.runloop.balancer.targets"] = "kong/runloop/balancer/targets.lua",
|
||||
["kong.runloop.balancer.upstreams"] = "kong/runloop/balancer/upstreams.lua",
|
||||
["kong.runloop.plugin_servers"] = "kong/runloop/plugin_servers/init.lua",
|
||||
["kong.runloop.plugin_servers.process"] = "kong/runloop/plugin_servers/process.lua",
|
||||
["kong.runloop.plugin_servers.mp_rpc"] = "kong/runloop/plugin_servers/mp_rpc.lua",
|
||||
["kong.runloop.plugin_servers.pb_rpc"] = "kong/runloop/plugin_servers/pb_rpc.lua",
|
||||
["kong.runloop.wasm"] = "kong/runloop/wasm.lua",
|
||||
["kong.runloop.wasm.properties"] = "kong/runloop/wasm/properties.lua",
|
||||
|
||||
["kong.workspaces"] = "kong/workspaces/init.lua",
|
||||
|
||||
["kong.db"] = "kong/db/init.lua",
|
||||
["kong.db.utils"] = "kong/db/utils.lua",
|
||||
["kong.db.errors"] = "kong/db/errors.lua",
|
||||
["kong.db.iteration"] = "kong/db/iteration.lua",
|
||||
["kong.db.dao"] = "kong/db/dao/init.lua",
|
||||
["kong.db.dao.certificates"] = "kong/db/dao/certificates.lua",
|
||||
["kong.db.dao.snis"] = "kong/db/dao/snis.lua",
|
||||
["kong.db.dao.targets"] = "kong/db/dao/targets.lua",
|
||||
["kong.db.dao.plugins"] = "kong/db/dao/plugins.lua",
|
||||
["kong.db.dao.tags"] = "kong/db/dao/tags.lua",
|
||||
["kong.db.dao.vaults"] = "kong/db/dao/vaults.lua",
|
||||
["kong.db.dao.workspaces"] = "kong/db/dao/workspaces.lua",
|
||||
["kong.db.dao.services"] = "kong/db/dao/services.lua",
|
||||
["kong.db.dao.ca_certificates"] = "kong/db/dao/ca_certificates.lua",
|
||||
["kong.db.declarative"] = "kong/db/declarative/init.lua",
|
||||
["kong.db.declarative.marshaller"] = "kong/db/declarative/marshaller.lua",
|
||||
["kong.db.declarative.export"] = "kong/db/declarative/export.lua",
|
||||
["kong.db.declarative.import"] = "kong/db/declarative/import.lua",
|
||||
["kong.db.schema"] = "kong/db/schema/init.lua",
|
||||
["kong.db.dao.keys"] = "kong/db/dao/keys.lua",
|
||||
["kong.db.dao.key_sets"] = "kong/db/dao/key_sets.lua",
|
||||
["kong.db.schema.entities.keys"] = "kong/db/schema/entities/keys.lua",
|
||||
["kong.db.schema.entities.key_sets"] = "kong/db/schema/entities/key_sets.lua",
|
||||
["kong.db.schema.entities.consumers"] = "kong/db/schema/entities/consumers.lua",
|
||||
["kong.db.schema.entities.routes"] = "kong/db/schema/entities/routes.lua",
|
||||
["kong.db.schema.entities.routes_subschemas"] = "kong/db/schema/entities/routes_subschemas.lua",
|
||||
["kong.db.schema.entities.services"] = "kong/db/schema/entities/services.lua",
|
||||
["kong.db.schema.entities.certificates"] = "kong/db/schema/entities/certificates.lua",
|
||||
["kong.db.schema.entities.snis"] = "kong/db/schema/entities/snis.lua",
|
||||
["kong.db.schema.entities.upstreams"] = "kong/db/schema/entities/upstreams.lua",
|
||||
["kong.db.schema.entities.targets"] = "kong/db/schema/entities/targets.lua",
|
||||
["kong.db.schema.entities.plugins"] = "kong/db/schema/entities/plugins.lua",
|
||||
["kong.db.schema.entities.tags"] = "kong/db/schema/entities/tags.lua",
|
||||
["kong.db.schema.entities.ca_certificates"] = "kong/db/schema/entities/ca_certificates.lua",
|
||||
["kong.db.schema.entities.vaults"] = "kong/db/schema/entities/vaults.lua",
|
||||
["kong.db.schema.entities.workspaces"] = "kong/db/schema/entities/workspaces.lua",
|
||||
["kong.db.schema.entities.clustering_data_planes"] = "kong/db/schema/entities/clustering_data_planes.lua",
|
||||
["kong.db.schema.entities.parameters"] = "kong/db/schema/entities/parameters.lua",
|
||||
["kong.db.schema.entities.filter_chains"] = "kong/db/schema/entities/filter_chains.lua",
|
||||
["kong.db.schema.json"] = "kong/db/schema/json.lua",
|
||||
["kong.db.schema.others.migrations"] = "kong/db/schema/others/migrations.lua",
|
||||
["kong.db.schema.others.declarative_config"] = "kong/db/schema/others/declarative_config.lua",
|
||||
["kong.db.schema.entity"] = "kong/db/schema/entity.lua",
|
||||
["kong.db.schema.metaschema"] = "kong/db/schema/metaschema.lua",
|
||||
["kong.db.schema.typedefs"] = "kong/db/schema/typedefs.lua",
|
||||
["kong.db.schema.plugin_loader"] = "kong/db/schema/plugin_loader.lua",
|
||||
["kong.db.schema.vault_loader"] = "kong/db/schema/vault_loader.lua",
|
||||
["kong.db.schema.topological_sort"] = "kong/db/schema/topological_sort.lua",
|
||||
["kong.db.strategies"] = "kong/db/strategies/init.lua",
|
||||
["kong.db.strategies.connector"] = "kong/db/strategies/connector.lua",
|
||||
["kong.db.strategies.postgres"] = "kong/db/strategies/postgres/init.lua",
|
||||
["kong.db.strategies.postgres.connector"] = "kong/db/strategies/postgres/connector.lua",
|
||||
["kong.db.strategies.postgres.tags"] = "kong/db/strategies/postgres/tags.lua",
|
||||
["kong.db.strategies.postgres.services"] = "kong/db/strategies/postgres/services.lua",
|
||||
["kong.db.strategies.postgres.plugins"] = "kong/db/strategies/postgres/plugins.lua",
|
||||
["kong.db.strategies.off"] = "kong/db/strategies/off/init.lua",
|
||||
["kong.db.strategies.off.connector"] = "kong/db/strategies/off/connector.lua",
|
||||
["kong.db.strategies.off.tags"] = "kong/db/strategies/off/tags.lua",
|
||||
|
||||
["kong.db.migrations.state"] = "kong/db/migrations/state.lua",
|
||||
["kong.db.migrations.subsystems"] = "kong/db/migrations/subsystems.lua",
|
||||
["kong.db.migrations.core"] = "kong/db/migrations/core/init.lua",
|
||||
["kong.db.migrations.core.000_base"] = "kong/db/migrations/core/000_base.lua",
|
||||
["kong.db.migrations.core.003_100_to_110"] = "kong/db/migrations/core/003_100_to_110.lua",
|
||||
["kong.db.migrations.core.004_110_to_120"] = "kong/db/migrations/core/004_110_to_120.lua",
|
||||
["kong.db.migrations.core.005_120_to_130"] = "kong/db/migrations/core/005_120_to_130.lua",
|
||||
["kong.db.migrations.core.006_130_to_140"] = "kong/db/migrations/core/006_130_to_140.lua",
|
||||
["kong.db.migrations.core.007_140_to_150"] = "kong/db/migrations/core/007_140_to_150.lua",
|
||||
["kong.db.migrations.core.008_150_to_200"] = "kong/db/migrations/core/008_150_to_200.lua",
|
||||
["kong.db.migrations.core.009_200_to_210"] = "kong/db/migrations/core/009_200_to_210.lua",
|
||||
["kong.db.migrations.core.010_210_to_211"] = "kong/db/migrations/core/010_210_to_211.lua",
|
||||
["kong.db.migrations.core.011_212_to_213"] = "kong/db/migrations/core/011_212_to_213.lua",
|
||||
["kong.db.migrations.core.012_213_to_220"] = "kong/db/migrations/core/012_213_to_220.lua",
|
||||
["kong.db.migrations.core.013_220_to_230"] = "kong/db/migrations/core/013_220_to_230.lua",
|
||||
["kong.db.migrations.core.014_230_to_270"] = "kong/db/migrations/core/014_230_to_270.lua",
|
||||
["kong.db.migrations.core.015_270_to_280"] = "kong/db/migrations/core/015_270_to_280.lua",
|
||||
["kong.db.migrations.core.016_280_to_300"] = "kong/db/migrations/core/016_280_to_300.lua",
|
||||
["kong.db.migrations.core.017_300_to_310"] = "kong/db/migrations/core/017_300_to_310.lua",
|
||||
["kong.db.migrations.core.018_310_to_320"] = "kong/db/migrations/core/018_310_to_320.lua",
|
||||
["kong.db.migrations.core.019_320_to_330"] = "kong/db/migrations/core/019_320_to_330.lua",
|
||||
["kong.db.migrations.core.020_330_to_340"] = "kong/db/migrations/core/020_330_to_340.lua",
|
||||
["kong.db.migrations.core.021_340_to_350"] = "kong/db/migrations/core/021_340_to_350.lua",
|
||||
["kong.db.migrations.core.022_350_to_360"] = "kong/db/migrations/core/022_350_to_360.lua",
|
||||
["kong.db.migrations.operations.200_to_210"] = "kong/db/migrations/operations/200_to_210.lua",
|
||||
["kong.db.migrations.operations.212_to_213"] = "kong/db/migrations/operations/212_to_213.lua",
|
||||
["kong.db.migrations.operations.280_to_300"] = "kong/db/migrations/operations/280_to_300.lua",
|
||||
["kong.db.migrations.migrate_path_280_300"] = "kong/db/migrations/migrate_path_280_300.lua",
|
||||
["kong.db.declarative.migrations"] = "kong/db/declarative/migrations/init.lua",
|
||||
["kong.db.declarative.migrations.route_path"] = "kong/db/declarative/migrations/route_path.lua",
|
||||
|
||||
["kong.pdk"] = "kong/pdk/init.lua",
|
||||
["kong.pdk.private.checks"] = "kong/pdk/private/checks.lua",
|
||||
["kong.pdk.private.phases"] = "kong/pdk/private/phases.lua",
|
||||
["kong.pdk.private.node"] = "kong/pdk/private/node.lua",
|
||||
["kong.pdk.client"] = "kong/pdk/client.lua",
|
||||
["kong.pdk.client.tls"] = "kong/pdk/client/tls.lua",
|
||||
["kong.pdk.ctx"] = "kong/pdk/ctx.lua",
|
||||
["kong.pdk.ip"] = "kong/pdk/ip.lua",
|
||||
["kong.pdk.log"] = "kong/pdk/log.lua",
|
||||
["kong.pdk.service"] = "kong/pdk/service.lua",
|
||||
["kong.pdk.service.request"] = "kong/pdk/service/request.lua",
|
||||
["kong.pdk.service.response"] = "kong/pdk/service/response.lua",
|
||||
["kong.pdk.router"] = "kong/pdk/router.lua",
|
||||
["kong.pdk.request"] = "kong/pdk/request.lua",
|
||||
["kong.pdk.response"] = "kong/pdk/response.lua",
|
||||
["kong.pdk.table"] = "kong/pdk/table.lua",
|
||||
["kong.pdk.node"] = "kong/pdk/node.lua",
|
||||
["kong.pdk.nginx"] = "kong/pdk/nginx.lua",
|
||||
["kong.pdk.cluster"] = "kong/pdk/cluster.lua",
|
||||
["kong.pdk.vault"] = "kong/pdk/vault.lua",
|
||||
["kong.pdk.tracing"] = "kong/pdk/tracing.lua",
|
||||
["kong.pdk.plugin"] = "kong/pdk/plugin.lua",
|
||||
|
||||
["kong.plugins.basic-auth.migrations"] = "kong/plugins/basic-auth/migrations/init.lua",
|
||||
["kong.plugins.basic-auth.migrations.000_base_basic_auth"] = "kong/plugins/basic-auth/migrations/000_base_basic_auth.lua",
|
||||
["kong.plugins.basic-auth.migrations.002_130_to_140"] = "kong/plugins/basic-auth/migrations/002_130_to_140.lua",
|
||||
["kong.plugins.basic-auth.migrations.003_200_to_210"] = "kong/plugins/basic-auth/migrations/003_200_to_210.lua",
|
||||
["kong.plugins.basic-auth.crypto"] = "kong/plugins/basic-auth/crypto.lua",
|
||||
["kong.plugins.basic-auth.handler"] = "kong/plugins/basic-auth/handler.lua",
|
||||
["kong.plugins.basic-auth.access"] = "kong/plugins/basic-auth/access.lua",
|
||||
["kong.plugins.basic-auth.schema"] = "kong/plugins/basic-auth/schema.lua",
|
||||
["kong.plugins.basic-auth.daos"] = "kong/plugins/basic-auth/daos.lua",
|
||||
|
||||
["kong.plugins.key-auth.migrations"] = "kong/plugins/key-auth/migrations/init.lua",
|
||||
["kong.plugins.key-auth.migrations.000_base_key_auth"] = "kong/plugins/key-auth/migrations/000_base_key_auth.lua",
|
||||
["kong.plugins.key-auth.migrations.002_130_to_140"] = "kong/plugins/key-auth/migrations/002_130_to_140.lua",
|
||||
["kong.plugins.key-auth.migrations.003_200_to_210"] = "kong/plugins/key-auth/migrations/003_200_to_210.lua",
|
||||
["kong.plugins.key-auth.migrations.004_320_to_330"] = "kong/plugins/key-auth/migrations/004_320_to_330.lua",
|
||||
["kong.plugins.key-auth.handler"] = "kong/plugins/key-auth/handler.lua",
|
||||
["kong.plugins.key-auth.schema"] = "kong/plugins/key-auth/schema.lua",
|
||||
["kong.plugins.key-auth.daos"] = "kong/plugins/key-auth/daos.lua",
|
||||
|
||||
["kong.plugins.oauth2.migrations"] = "kong/plugins/oauth2/migrations/init.lua",
|
||||
["kong.plugins.oauth2.migrations.000_base_oauth2"] = "kong/plugins/oauth2/migrations/000_base_oauth2.lua",
|
||||
["kong.plugins.oauth2.migrations.003_130_to_140"] = "kong/plugins/oauth2/migrations/003_130_to_140.lua",
|
||||
["kong.plugins.oauth2.migrations.004_200_to_210"] = "kong/plugins/oauth2/migrations/004_200_to_210.lua",
|
||||
["kong.plugins.oauth2.migrations.005_210_to_211"] = "kong/plugins/oauth2/migrations/005_210_to_211.lua",
|
||||
["kong.plugins.oauth2.migrations.006_320_to_330"] = "kong/plugins/oauth2/migrations/006_320_to_330.lua",
|
||||
["kong.plugins.oauth2.migrations.007_320_to_330"] = "kong/plugins/oauth2/migrations/007_320_to_330.lua",
|
||||
["kong.plugins.oauth2.handler"] = "kong/plugins/oauth2/handler.lua",
|
||||
["kong.plugins.oauth2.secret"] = "kong/plugins/oauth2/secret.lua",
|
||||
["kong.plugins.oauth2.access"] = "kong/plugins/oauth2/access.lua",
|
||||
["kong.plugins.oauth2.schema"] = "kong/plugins/oauth2/schema.lua",
|
||||
["kong.plugins.oauth2.daos"] = "kong/plugins/oauth2/daos.lua",
|
||||
["kong.plugins.oauth2.daos.oauth2_tokens"] = "kong/plugins/oauth2/daos/oauth2_tokens.lua",
|
||||
|
||||
["kong.plugins.tcp-log.handler"] = "kong/plugins/tcp-log/handler.lua",
|
||||
["kong.plugins.tcp-log.schema"] = "kong/plugins/tcp-log/schema.lua",
|
||||
|
||||
["kong.plugins.udp-log.handler"] = "kong/plugins/udp-log/handler.lua",
|
||||
["kong.plugins.udp-log.schema"] = "kong/plugins/udp-log/schema.lua",
|
||||
|
||||
["kong.plugins.http-log.handler"] = "kong/plugins/http-log/handler.lua",
|
||||
["kong.plugins.http-log.schema"] = "kong/plugins/http-log/schema.lua",
|
||||
["kong.plugins.http-log.migrations"] = "kong/plugins/http-log/migrations/init.lua",
|
||||
["kong.plugins.http-log.migrations.001_280_to_300"] = "kong/plugins/http-log/migrations/001_280_to_300.lua",
|
||||
|
||||
["kong.plugins.file-log.handler"] = "kong/plugins/file-log/handler.lua",
|
||||
["kong.plugins.file-log.schema"] = "kong/plugins/file-log/schema.lua",
|
||||
|
||||
["kong.plugins.rate-limiting.migrations"] = "kong/plugins/rate-limiting/migrations/init.lua",
|
||||
["kong.plugins.rate-limiting.migrations.000_base_rate_limiting"] = "kong/plugins/rate-limiting/migrations/000_base_rate_limiting.lua",
|
||||
["kong.plugins.rate-limiting.migrations.003_10_to_112"] = "kong/plugins/rate-limiting/migrations/003_10_to_112.lua",
|
||||
["kong.plugins.rate-limiting.migrations.004_200_to_210"] = "kong/plugins/rate-limiting/migrations/004_200_to_210.lua",
|
||||
["kong.plugins.rate-limiting.migrations.005_320_to_330"] = "kong/plugins/rate-limiting/migrations/005_320_to_330.lua",
|
||||
["kong.plugins.rate-limiting.migrations.006_350_to_360"] = "kong/plugins/rate-limiting/migrations/006_350_to_360.lua",
|
||||
["kong.plugins.rate-limiting.expiration"] = "kong/plugins/rate-limiting/expiration.lua",
|
||||
["kong.plugins.rate-limiting.handler"] = "kong/plugins/rate-limiting/handler.lua",
|
||||
["kong.plugins.rate-limiting.schema"] = "kong/plugins/rate-limiting/schema.lua",
|
||||
["kong.plugins.rate-limiting.daos"] = "kong/plugins/rate-limiting/daos.lua",
|
||||
["kong.plugins.rate-limiting.policies"] = "kong/plugins/rate-limiting/policies/init.lua",
|
||||
["kong.plugins.rate-limiting.policies.cluster"] = "kong/plugins/rate-limiting/policies/cluster.lua",
|
||||
["kong.plugins.rate-limiting.clustering.compat.redis_translation"] = "kong/plugins/rate-limiting/clustering/compat/redis_translation.lua",
|
||||
|
||||
["kong.plugins.response-ratelimiting.migrations"] = "kong/plugins/response-ratelimiting/migrations/init.lua",
|
||||
["kong.plugins.response-ratelimiting.migrations.000_base_response_rate_limiting"] = "kong/plugins/response-ratelimiting/migrations/000_base_response_rate_limiting.lua",
|
||||
["kong.plugins.response-ratelimiting.migrations.001_350_to_360"] = "kong/plugins/response-ratelimiting/migrations/001_350_to_360.lua",
|
||||
["kong.plugins.response-ratelimiting.handler"] = "kong/plugins/response-ratelimiting/handler.lua",
|
||||
["kong.plugins.response-ratelimiting.access"] = "kong/plugins/response-ratelimiting/access.lua",
|
||||
["kong.plugins.response-ratelimiting.header_filter"] = "kong/plugins/response-ratelimiting/header_filter.lua",
|
||||
["kong.plugins.response-ratelimiting.log"] = "kong/plugins/response-ratelimiting/log.lua",
|
||||
["kong.plugins.response-ratelimiting.schema"] = "kong/plugins/response-ratelimiting/schema.lua",
|
||||
["kong.plugins.response-ratelimiting.policies"] = "kong/plugins/response-ratelimiting/policies/init.lua",
|
||||
["kong.plugins.response-ratelimiting.policies.cluster"] = "kong/plugins/response-ratelimiting/policies/cluster.lua",
|
||||
["kong.plugins.response-ratelimiting.clustering.compat.redis_translation"] = "kong/plugins/response-ratelimiting/clustering/compat/redis_translation.lua",
|
||||
|
||||
["kong.plugins.request-size-limiting.handler"] = "kong/plugins/request-size-limiting/handler.lua",
|
||||
["kong.plugins.request-size-limiting.schema"] = "kong/plugins/request-size-limiting/schema.lua",
|
||||
|
||||
["kong.plugins.response-transformer.handler"] = "kong/plugins/response-transformer/handler.lua",
|
||||
["kong.plugins.response-transformer.body_transformer"] = "kong/plugins/response-transformer/body_transformer.lua",
|
||||
["kong.plugins.response-transformer.header_transformer"] = "kong/plugins/response-transformer/header_transformer.lua",
|
||||
["kong.plugins.response-transformer.schema"] = "kong/plugins/response-transformer/schema.lua",
|
||||
|
||||
["kong.plugins.cors.handler"] = "kong/plugins/cors/handler.lua",
|
||||
["kong.plugins.cors.schema"] = "kong/plugins/cors/schema.lua",
|
||||
|
||||
["kong.plugins.ip-restriction.handler"] = "kong/plugins/ip-restriction/handler.lua",
|
||||
["kong.plugins.ip-restriction.schema"] = "kong/plugins/ip-restriction/schema.lua",
|
||||
["kong.plugins.ip-restriction.migrations"] = "kong/plugins/ip-restriction/migrations/init.lua",
|
||||
["kong.plugins.ip-restriction.migrations.001_200_to_210"] = "kong/plugins/ip-restriction/migrations/001_200_to_210.lua",
|
||||
|
||||
["kong.plugins.acl.migrations"] = "kong/plugins/acl/migrations/init.lua",
|
||||
["kong.plugins.acl.migrations.000_base_acl"] = "kong/plugins/acl/migrations/000_base_acl.lua",
|
||||
["kong.plugins.acl.migrations.002_130_to_140"] = "kong/plugins/acl/migrations/002_130_to_140.lua",
|
||||
["kong.plugins.acl.migrations.003_200_to_210"] = "kong/plugins/acl/migrations/003_200_to_210.lua",
|
||||
["kong.plugins.acl.migrations.004_212_to_213"] = "kong/plugins/acl/migrations/004_212_to_213.lua",
|
||||
["kong.plugins.acl.handler"] = "kong/plugins/acl/handler.lua",
|
||||
["kong.plugins.acl.schema"] = "kong/plugins/acl/schema.lua",
|
||||
["kong.plugins.acl.daos"] = "kong/plugins/acl/daos.lua",
|
||||
["kong.plugins.acl.groups"] = "kong/plugins/acl/groups.lua",
|
||||
["kong.plugins.acl.acls"] = "kong/plugins/acl/acls.lua",
|
||||
["kong.plugins.acl.api"] = "kong/plugins/acl/api.lua",
|
||||
|
||||
["kong.plugins.correlation-id.handler"] = "kong/plugins/correlation-id/handler.lua",
|
||||
["kong.plugins.correlation-id.schema"] = "kong/plugins/correlation-id/schema.lua",
|
||||
|
||||
["kong.plugins.jwt.migrations"] = "kong/plugins/jwt/migrations/init.lua",
|
||||
["kong.plugins.jwt.migrations.000_base_jwt"] = "kong/plugins/jwt/migrations/000_base_jwt.lua",
|
||||
["kong.plugins.jwt.migrations.002_130_to_140"] = "kong/plugins/jwt/migrations/002_130_to_140.lua",
|
||||
["kong.plugins.jwt.migrations.003_200_to_210"] = "kong/plugins/jwt/migrations/003_200_to_210.lua",
|
||||
["kong.plugins.jwt.handler"] = "kong/plugins/jwt/handler.lua",
|
||||
["kong.plugins.jwt.schema"] = "kong/plugins/jwt/schema.lua",
|
||||
["kong.plugins.jwt.daos"] = "kong/plugins/jwt/daos.lua",
|
||||
["kong.plugins.jwt.jwt_parser"] = "kong/plugins/jwt/jwt_parser.lua",
|
||||
|
||||
["kong.plugins.hmac-auth.migrations"] = "kong/plugins/hmac-auth/migrations/init.lua",
|
||||
["kong.plugins.hmac-auth.migrations.000_base_hmac_auth"] = "kong/plugins/hmac-auth/migrations/000_base_hmac_auth.lua",
|
||||
["kong.plugins.hmac-auth.migrations.002_130_to_140"] = "kong/plugins/hmac-auth/migrations/002_130_to_140.lua",
|
||||
["kong.plugins.hmac-auth.migrations.003_200_to_210"] = "kong/plugins/hmac-auth/migrations/003_200_to_210.lua",
|
||||
["kong.plugins.hmac-auth.handler"] = "kong/plugins/hmac-auth/handler.lua",
|
||||
["kong.plugins.hmac-auth.access"] = "kong/plugins/hmac-auth/access.lua",
|
||||
["kong.plugins.hmac-auth.schema"] = "kong/plugins/hmac-auth/schema.lua",
|
||||
["kong.plugins.hmac-auth.daos"] = "kong/plugins/hmac-auth/daos.lua",
|
||||
|
||||
["kong.plugins.ldap-auth.handler"] = "kong/plugins/ldap-auth/handler.lua",
|
||||
["kong.plugins.ldap-auth.access"] = "kong/plugins/ldap-auth/access.lua",
|
||||
["kong.plugins.ldap-auth.schema"] = "kong/plugins/ldap-auth/schema.lua",
|
||||
["kong.plugins.ldap-auth.ldap"] = "kong/plugins/ldap-auth/ldap.lua",
|
||||
["kong.plugins.ldap-auth.asn1"] = "kong/plugins/ldap-auth/asn1.lua",
|
||||
|
||||
["kong.plugins.syslog.handler"] = "kong/plugins/syslog/handler.lua",
|
||||
["kong.plugins.syslog.schema"] = "kong/plugins/syslog/schema.lua",
|
||||
|
||||
["kong.plugins.loggly.handler"] = "kong/plugins/loggly/handler.lua",
|
||||
["kong.plugins.loggly.schema"] = "kong/plugins/loggly/schema.lua",
|
||||
|
||||
["kong.plugins.datadog.handler"] = "kong/plugins/datadog/handler.lua",
|
||||
["kong.plugins.datadog.schema"] = "kong/plugins/datadog/schema.lua",
|
||||
["kong.plugins.datadog.statsd_logger"] = "kong/plugins/datadog/statsd_logger.lua",
|
||||
|
||||
["kong.plugins.statsd.constants"] = "kong/plugins/statsd/constants.lua",
|
||||
["kong.plugins.statsd.handler"] = "kong/plugins/statsd/handler.lua",
|
||||
["kong.plugins.statsd.log"] = "kong/plugins/statsd/log.lua",
|
||||
["kong.plugins.statsd.schema"] = "kong/plugins/statsd/schema.lua",
|
||||
["kong.plugins.statsd.statsd_logger"] = "kong/plugins/statsd/statsd_logger.lua",
|
||||
|
||||
["kong.plugins.bot-detection.handler"] = "kong/plugins/bot-detection/handler.lua",
|
||||
["kong.plugins.bot-detection.schema"] = "kong/plugins/bot-detection/schema.lua",
|
||||
["kong.plugins.bot-detection.rules"] = "kong/plugins/bot-detection/rules.lua",
|
||||
["kong.plugins.bot-detection.migrations"] = "kong/plugins/bot-detection/migrations/init.lua",
|
||||
["kong.plugins.bot-detection.migrations.001_200_to_210"] = "kong/plugins/bot-detection/migrations/001_200_to_210.lua",
|
||||
|
||||
["kong.plugins.request-termination.handler"] = "kong/plugins/request-termination/handler.lua",
|
||||
["kong.plugins.request-termination.schema"] = "kong/plugins/request-termination/schema.lua",
|
||||
|
||||
["kong.plugins.aws-lambda.handler"] = "kong/plugins/aws-lambda/handler.lua",
|
||||
["kong.plugins.aws-lambda.schema"] = "kong/plugins/aws-lambda/schema.lua",
|
||||
["kong.plugins.aws-lambda.request-util"] = "kong/plugins/aws-lambda/request-util.lua",
|
||||
|
||||
["kong.plugins.grpc-gateway.deco"] = "kong/plugins/grpc-gateway/deco.lua",
|
||||
["kong.plugins.grpc-gateway.handler"] = "kong/plugins/grpc-gateway/handler.lua",
|
||||
["kong.plugins.grpc-gateway.schema"] = "kong/plugins/grpc-gateway/schema.lua",
|
||||
|
||||
["kong.plugins.acme.api"] = "kong/plugins/acme/api.lua",
|
||||
["kong.plugins.acme.client"] = "kong/plugins/acme/client.lua",
|
||||
["kong.plugins.acme.clustering.compat.redis_translation"] = "kong/plugins/acme/clustering/compat/redis_translation.lua",
|
||||
["kong.plugins.acme.daos"] = "kong/plugins/acme/daos.lua",
|
||||
["kong.plugins.acme.handler"] = "kong/plugins/acme/handler.lua",
|
||||
["kong.plugins.acme.migrations.000_base_acme"] = "kong/plugins/acme/migrations/000_base_acme.lua",
|
||||
["kong.plugins.acme.migrations.001_280_to_300"] = "kong/plugins/acme/migrations/001_280_to_300.lua",
|
||||
["kong.plugins.acme.migrations.002_320_to_330"] = "kong/plugins/acme/migrations/002_320_to_330.lua",
|
||||
["kong.plugins.acme.migrations.003_350_to_360"] = "kong/plugins/acme/migrations/003_350_to_360.lua",
|
||||
["kong.plugins.acme.migrations"] = "kong/plugins/acme/migrations/init.lua",
|
||||
["kong.plugins.acme.schema"] = "kong/plugins/acme/schema.lua",
|
||||
["kong.plugins.acme.storage.kong"] = "kong/plugins/acme/storage/kong.lua",
|
||||
["kong.plugins.acme.storage.config_adapters"] = "kong/plugins/acme/storage/config_adapters/init.lua",
|
||||
["kong.plugins.acme.storage.config_adapters.redis"] = "kong/plugins/acme/storage/config_adapters/redis.lua",
|
||||
["kong.plugins.acme.reserved_words"] = "kong/plugins/acme/reserved_words.lua",
|
||||
|
||||
["kong.plugins.prometheus.api"] = "kong/plugins/prometheus/api.lua",
|
||||
["kong.plugins.prometheus.status_api"] = "kong/plugins/prometheus/status_api.lua",
|
||||
["kong.plugins.prometheus.exporter"] = "kong/plugins/prometheus/exporter.lua",
|
||||
["kong.plugins.prometheus.handler"] = "kong/plugins/prometheus/handler.lua",
|
||||
["kong.plugins.prometheus.prometheus"] = "kong/plugins/prometheus/prometheus.lua",
|
||||
["kong.plugins.prometheus.serve"] = "kong/plugins/prometheus/serve.lua",
|
||||
["kong.plugins.prometheus.schema"] = "kong/plugins/prometheus/schema.lua",
|
||||
|
||||
["kong.plugins.session.handler"] = "kong/plugins/session/handler.lua",
|
||||
["kong.plugins.session.schema"] = "kong/plugins/session/schema.lua",
|
||||
["kong.plugins.session.access"] = "kong/plugins/session/access.lua",
|
||||
["kong.plugins.session.header_filter"] = "kong/plugins/session/header_filter.lua",
|
||||
["kong.plugins.session.session"] = "kong/plugins/session/session.lua",
|
||||
["kong.plugins.session.daos"] = "kong/plugins/session/daos.lua",
|
||||
["kong.plugins.session.storage.kong"] = "kong/plugins/session/storage/kong.lua",
|
||||
["kong.plugins.session.migrations.000_base_session"] = "kong/plugins/session/migrations/000_base_session.lua",
|
||||
["kong.plugins.session.migrations.001_add_ttl_index"] = "kong/plugins/session/migrations/001_add_ttl_index.lua",
|
||||
["kong.plugins.session.migrations.002_320_to_330"] = "kong/plugins/session/migrations/002_320_to_330.lua",
|
||||
["kong.plugins.session.migrations"] = "kong/plugins/session/migrations/init.lua",
|
||||
|
||||
["kong.plugins.proxy-cache.handler"] = "kong/plugins/proxy-cache/handler.lua",
|
||||
["kong.plugins.proxy-cache.cache_key"] = "kong/plugins/proxy-cache/cache_key.lua",
|
||||
["kong.plugins.proxy-cache.schema"] = "kong/plugins/proxy-cache/schema.lua",
|
||||
["kong.plugins.proxy-cache.api"] = "kong/plugins/proxy-cache/api.lua",
|
||||
["kong.plugins.proxy-cache.strategies"] = "kong/plugins/proxy-cache/strategies/init.lua",
|
||||
["kong.plugins.proxy-cache.strategies.memory"] = "kong/plugins/proxy-cache/strategies/memory.lua",
|
||||
|
||||
["kong.plugins.grpc-web.deco"] = "kong/plugins/grpc-web/deco.lua",
|
||||
["kong.plugins.grpc-web.handler"] = "kong/plugins/grpc-web/handler.lua",
|
||||
["kong.plugins.grpc-web.schema"] = "kong/plugins/grpc-web/schema.lua",
|
||||
|
||||
["kong.plugins.pre-function._handler"] = "kong/plugins/pre-function/_handler.lua",
|
||||
["kong.plugins.pre-function._schema"] = "kong/plugins/pre-function/_schema.lua",
|
||||
["kong.plugins.pre-function.migrations._001_280_to_300"] = "kong/plugins/pre-function/migrations/_001_280_to_300.lua",
|
||||
|
||||
["kong.plugins.pre-function.handler"] = "kong/plugins/pre-function/handler.lua",
|
||||
["kong.plugins.pre-function.schema"] = "kong/plugins/pre-function/schema.lua",
|
||||
["kong.plugins.pre-function.migrations"] = "kong/plugins/pre-function/migrations/init.lua",
|
||||
["kong.plugins.pre-function.migrations.001_280_to_300"] = "kong/plugins/pre-function/migrations/001_280_to_300.lua",
|
||||
|
||||
["kong.plugins.post-function.handler"] = "kong/plugins/post-function/handler.lua",
|
||||
["kong.plugins.post-function.schema"] = "kong/plugins/post-function/schema.lua",
|
||||
["kong.plugins.post-function.migrations"] = "kong/plugins/post-function/migrations/init.lua",
|
||||
["kong.plugins.post-function.migrations.001_280_to_300"] = "kong/plugins/post-function/migrations/001_280_to_300.lua",
|
||||
|
||||
["kong.plugins.zipkin.handler"] = "kong/plugins/zipkin/handler.lua",
|
||||
["kong.plugins.zipkin.reporter"] = "kong/plugins/zipkin/reporter.lua",
|
||||
["kong.plugins.zipkin.span"] = "kong/plugins/zipkin/span.lua",
|
||||
["kong.plugins.zipkin.schema"] = "kong/plugins/zipkin/schema.lua",
|
||||
["kong.plugins.zipkin.request_tags"] = "kong/plugins/zipkin/request_tags.lua",
|
||||
|
||||
["kong.plugins.request-transformer.migrations.postgres"] = "kong/plugins/request-transformer/migrations/postgres.lua",
|
||||
["kong.plugins.request-transformer.migrations.common"] = "kong/plugins/request-transformer/migrations/common.lua",
|
||||
["kong.plugins.request-transformer.handler"] = "kong/plugins/request-transformer/handler.lua",
|
||||
["kong.plugins.request-transformer.access"] = "kong/plugins/request-transformer/access.lua",
|
||||
["kong.plugins.request-transformer.schema"] = "kong/plugins/request-transformer/schema.lua",
|
||||
|
||||
["kong.plugins.azure-functions.handler"] = "kong/plugins/azure-functions/handler.lua",
|
||||
["kong.plugins.azure-functions.schema"] = "kong/plugins/azure-functions/schema.lua",
|
||||
|
||||
["kong.plugins.opentelemetry.handler"] = "kong/plugins/opentelemetry/handler.lua",
|
||||
["kong.plugins.opentelemetry.schema"] = "kong/plugins/opentelemetry/schema.lua",
|
||||
["kong.plugins.opentelemetry.proto"] = "kong/plugins/opentelemetry/proto.lua",
|
||||
["kong.plugins.opentelemetry.otlp"] = "kong/plugins/opentelemetry/otlp.lua",
|
||||
|
||||
["kong.plugins.ai-proxy.handler"] = "kong/plugins/ai-proxy/handler.lua",
|
||||
["kong.plugins.ai-proxy.schema"] = "kong/plugins/ai-proxy/schema.lua",
|
||||
|
||||
["kong.plugins.ai-request-transformer.handler"] = "kong/plugins/ai-request-transformer/handler.lua",
|
||||
["kong.plugins.ai-request-transformer.schema"] = "kong/plugins/ai-request-transformer/schema.lua",
|
||||
|
||||
["kong.plugins.ai-response-transformer.handler"] = "kong/plugins/ai-response-transformer/handler.lua",
|
||||
["kong.plugins.ai-response-transformer.schema"] = "kong/plugins/ai-response-transformer/schema.lua",
|
||||
|
||||
["kong.llm"] = "kong/llm/init.lua",
|
||||
["kong.llm.drivers.shared"] = "kong/llm/drivers/shared.lua",
|
||||
["kong.llm.drivers.openai"] = "kong/llm/drivers/openai.lua",
|
||||
["kong.llm.drivers.azure"] = "kong/llm/drivers/azure.lua",
|
||||
["kong.llm.drivers.cohere"] = "kong/llm/drivers/cohere.lua",
|
||||
["kong.llm.drivers.anthropic"] = "kong/llm/drivers/anthropic.lua",
|
||||
["kong.llm.drivers.mistral"] = "kong/llm/drivers/mistral.lua",
|
||||
["kong.llm.drivers.llama2"] = "kong/llm/drivers/llama2.lua",
|
||||
|
||||
["kong.plugins.ai-prompt-decorator.handler"] = "kong/plugins/ai-prompt-decorator/handler.lua",
|
||||
["kong.plugins.ai-prompt-decorator.schema"] = "kong/plugins/ai-prompt-decorator/schema.lua",
|
||||
|
||||
["kong.plugins.ai-prompt-template.handler"] = "kong/plugins/ai-prompt-template/handler.lua",
|
||||
["kong.plugins.ai-prompt-template.schema"] = "kong/plugins/ai-prompt-template/schema.lua",
|
||||
["kong.plugins.ai-prompt-template.templater"] = "kong/plugins/ai-prompt-template/templater.lua",
|
||||
|
||||
["kong.plugins.ai-prompt-guard.handler"] = "kong/plugins/ai-prompt-guard/handler.lua",
|
||||
["kong.plugins.ai-prompt-guard.schema"] = "kong/plugins/ai-prompt-guard/schema.lua",
|
||||
|
||||
["kong.vaults.env"] = "kong/vaults/env/init.lua",
|
||||
["kong.vaults.env.schema"] = "kong/vaults/env/schema.lua",
|
||||
|
||||
["kong.tracing.instrumentation"] = "kong/tracing/instrumentation.lua",
|
||||
["kong.tracing.propagation"] = "kong/tracing/propagation.lua",
|
||||
["kong.tracing.request_id"] = "kong/tracing/request_id.lua",
|
||||
["kong.tracing.tracing_context"] = "kong/tracing/tracing_context.lua",
|
||||
|
||||
["kong.timing"] = "kong/timing/init.lua",
|
||||
["kong.timing.context"] = "kong/timing/context.lua",
|
||||
["kong.timing.hooks"] = "kong/timing/hooks/init.lua",
|
||||
["kong.timing.hooks.dns"] = "kong/timing/hooks/dns.lua",
|
||||
["kong.timing.hooks.http"] = "kong/timing/hooks/http.lua",
|
||||
["kong.timing.hooks.redis"] = "kong/timing/hooks/redis.lua",
|
||||
["kong.timing.hooks.socket"] = "kong/timing/hooks/socket.lua",
|
||||
|
||||
["kong.dynamic_hook"] = "kong/dynamic_hook/init.lua",
|
||||
["kong.dynamic_hook.wrap_function_gen"] = "kong/dynamic_hook/wrap_function_gen.lua",
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ func catalogFixtureImageWithConfig(t *testing.T, fixtureImageName string, cfg *s
|
||||
cfg.CatalogerSelection = cfg.CatalogerSelection.WithDefaults(pkgcataloging.ImageTag)
|
||||
|
||||
// get the fixture image tar file
|
||||
imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
||||
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
|
||||
|
||||
// get the source to build an SBOM against
|
||||
|
||||
@@ -9,14 +9,14 @@ 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-20240522144804-d81e109008aa
|
||||
github.com/anchore/fangs v0.0.0-20240508143433-f016b099950f
|
||||
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.20240507183024-848e011fc24f
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240312213626-055233e539b4
|
||||
github.com/anchore/stereoscope v0.0.3-0.20240501181043-2e9894674185
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
||||
// we are hinting brotli to latest due to warning when installing archiver v3:
|
||||
@@ -24,12 +24,12 @@ require (
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1
|
||||
github.com/charmbracelet/bubbles v0.18.0
|
||||
github.com/charmbracelet/bubbletea v0.26.3
|
||||
github.com/charmbracelet/lipgloss v0.11.0
|
||||
github.com/charmbracelet/bubbletea v0.26.1
|
||||
github.com/charmbracelet/lipgloss v0.10.0
|
||||
github.com/dave/jennifer v1.7.0
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
|
||||
github.com/distribution/reference v0.6.0
|
||||
github.com/docker/docker v26.1.3+incompatible
|
||||
github.com/docker/docker v26.1.1+incompatible
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/elliotchance/phpserialize v1.4.0
|
||||
github.com/facebookincubator/nvdtools v0.1.5
|
||||
@@ -46,10 +46,10 @@ require (
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/iancoleman/strcase v0.3.0
|
||||
github.com/invopop/jsonschema v0.7.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.9
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.8
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
|
||||
github.com/knqyf263/go-rpmdb v0.1.1
|
||||
github.com/knqyf263/go-rpmdb v0.1.0
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
@@ -59,11 +59,10 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.22
|
||||
github.com/saferwall/pe v1.5.3
|
||||
github.com/saferwall/pe v1.5.2
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
|
||||
github.com/sanity-io/litter v1.5.5
|
||||
github.com/sassoftware/go-rpmutils v0.4.0
|
||||
github.com/sassoftware/go-rpmutils v0.3.0
|
||||
// pinned to pull in 386 arch fix: https://github.com/scylladb/go-set/commit/cc7b2070d91ebf40d233207b633e28f5bd8f03a5
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
|
||||
@@ -79,15 +78,11 @@ require (
|
||||
github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1
|
||||
go.uber.org/goleak v1.3.0
|
||||
golang.org/x/mod v0.17.0
|
||||
golang.org/x/net v0.25.0
|
||||
golang.org/x/net v0.24.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.29.10
|
||||
modernc.org/sqlite v1.29.8
|
||||
)
|
||||
|
||||
require google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
|
||||
require github.com/magiconair/properties v1.8.7
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
@@ -106,11 +101,7 @@ require (
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/becheran/wildmatch-go v1.0.0 // indirect
|
||||
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/input v0.1.0 // indirect
|
||||
github.com/charmbracelet/x/term v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.1.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.8 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/containerd/containerd v1.7.11 // indirect
|
||||
github.com/containerd/continuity v0.4.2 // indirect
|
||||
@@ -133,7 +124,7 @@ require (
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/felixge/fgprof v0.9.3 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.0 // indirect
|
||||
github.com/gkampitakis/ciinfo v0.3.0 // indirect
|
||||
github.com/gkampitakis/go-diff v1.3.2 // indirect
|
||||
@@ -155,12 +146,13 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/maruel/natural v1.1.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
@@ -193,17 +185,16 @@ require (
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect
|
||||
github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/skeema/knownhosts v1.2.2 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.18.2 // indirect
|
||||
github.com/spf13/viper v1.17.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/sylabs/sif/v2 v2.11.5 // indirect
|
||||
github.com/sylabs/squashfs v0.6.1 // indirect
|
||||
@@ -212,13 +203,14 @@ require (
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/ulikunitz/xz v0.5.11 // indirect
|
||||
github.com/vbatts/tar-split v0.11.3 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
|
||||
go.opentelemetry.io/otel v1.19.0 // indirect
|
||||
@@ -226,14 +218,15 @@ 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.23.0 // indirect
|
||||
golang.org/x/crypto v0.22.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/term v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/term v0.19.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.19.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
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
|
||||
@@ -93,10 +93,10 @@ 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-20240522144804-d81e109008aa h1:pwlAn4O9SBUnlgfa69YcqIynbUyobLVFYu8HxSoCffA=
|
||||
github.com/anchore/clio v0.0.0-20240522144804-d81e109008aa/go.mod h1:nD3H5uIvjxlfmakOBgtyFQbk5Zjp3l538kxfpHPslzI=
|
||||
github.com/anchore/fangs v0.0.0-20240508143433-f016b099950f h1:NOhzafCyNYFi88qxkBFjMzQo4dRa1vDhBzx+0Uovx8Q=
|
||||
github.com/anchore/fangs v0.0.0-20240508143433-f016b099950f/go.mod h1:sVpRS2yNCw6tLVpvA1QSDVWTJVpCuAm8JNZgn4Sjz/k=
|
||||
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=
|
||||
@@ -109,8 +109,8 @@ github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0v
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZVsCYMrIZBpFxwV26CbsuoEh5muXD5I1Ods=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240507183024-848e011fc24f h1:B/E9ixKNCasntpoch61NDaQyGPDXLEJlL+B9B/PbdbA=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240507183024-848e011fc24f/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240312213626-055233e539b4 h1:SjemQ90fgflz39HG+VMkNfrpUVJpcFW6ZFA3TDXqzBM=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240312213626-055233e539b4/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
|
||||
github.com/anchore/stereoscope v0.0.3-0.20240501181043-2e9894674185 h1:SuViDJ27nZ+joGdKbAkxAlm7tYMt9NTxTZZ05po4hls=
|
||||
github.com/anchore/stereoscope v0.0.3-0.20240501181043-2e9894674185/go.mod h1:ckIamHiRMp8iBwWoTtE5Xkt9VQ5QC+6+O4VzwqyZr5Q=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
@@ -155,20 +155,12 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
|
||||
github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
|
||||
github.com/charmbracelet/bubbletea v0.26.3 h1:iXyGvI+FfOWqkB2V07m1DF3xxQijxjY2j8PqiXYqasg=
|
||||
github.com/charmbracelet/bubbletea v0.26.3/go.mod h1:bpZHfDHTYJC5g+FBK+ptJRCQotRC+Dhh3AoMxa/2+3Q=
|
||||
github.com/charmbracelet/bubbletea v0.26.1 h1:xujcQeF73rh4jwu3+zhfQsvV18x+7zIjlw7/CYbzGJ0=
|
||||
github.com/charmbracelet/bubbletea v0.26.1/go.mod h1:FzKr7sKoO8iFVcdIBM9J0sJOcQv5nDQaYwsee3kpbgo=
|
||||
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g=
|
||||
github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8=
|
||||
github.com/charmbracelet/x/ansi v0.1.1 h1:CGAduulr6egay/YVbGc8Hsu8deMg1xZ/bkaXTPi1JDk=
|
||||
github.com/charmbracelet/x/ansi v0.1.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||
github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ=
|
||||
github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28=
|
||||
github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
|
||||
github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
|
||||
github.com/charmbracelet/x/windows v0.1.0 h1:gTaxdvzDM5oMa/I2ZNF7wN78X/atWemG9Wph7Ika2k4=
|
||||
github.com/charmbracelet/x/windows v0.1.0/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ=
|
||||
github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
|
||||
github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@@ -176,8 +168,8 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
|
||||
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@@ -229,8 +221,8 @@ github.com/docker/cli v24.0.0+incompatible h1:0+1VshNwBQzQAx9lOl+OYCTCEAD8fKs/qe
|
||||
github.com/docker/cli v24.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo=
|
||||
github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v26.1.1+incompatible h1:oI+4kkAgIwwb54b9OC7Xc3hSgu1RlJA/Lln/DF72djQ=
|
||||
github.com/docker/docker v26.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
@@ -277,11 +269,11 @@ github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0FnbhiOsEro=
|
||||
github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -481,8 +473,8 @@ github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy77
|
||||
github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+UV8OU=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.8 h1:8BCzJdSvUbaDuRba4YVh+SKMGcAAKdkcF3SVFbrHAtQ=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.8/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
|
||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
@@ -500,13 +492,13 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/knqyf263/go-rpmdb v0.1.1 h1:oh68mTCvp1XzxdU7EfafcWzzfstUZAEa3MW0IJye584=
|
||||
github.com/knqyf263/go-rpmdb v0.1.1/go.mod h1:9LQcoMCMQ9vrF7HcDtXfvqGO4+ddxFQ8+YF/0CVGDww=
|
||||
github.com/knqyf263/go-rpmdb v0.1.0 h1:pOgjtOGtW0B+ibY905hP3ETrYFmLZsHiReKsplcs+to=
|
||||
github.com/knqyf263/go-rpmdb v0.1.0/go.mod h1:9LQcoMCMQ9vrF7HcDtXfvqGO4+ddxFQ8+YF/0CVGDww=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
@@ -552,6 +544,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
@@ -666,8 +660,6 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
@@ -682,11 +674,11 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/saferwall/pe v1.5.3 h1:tZ2KJWeJK6N2jjJx+B9hm+wq6qe0o56pql2PXUaQ9eI=
|
||||
github.com/saferwall/pe v1.5.3/go.mod h1:mJx+PuptmNpoPFBNhWs/uDMFL/kTHVZIkg0d4OUJFbQ=
|
||||
github.com/saferwall/pe v1.5.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.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
|
||||
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f h1:MvTmaQdww/z0Q4wrYjDSCcZ78NoftLQyHBSLW/Cx79Y=
|
||||
@@ -695,15 +687,13 @@ github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
||||
github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
|
||||
github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
|
||||
github.com/sassoftware/go-rpmutils v0.3.0 h1:tE4TZ8KcOXay5iIP64P291s6Qxd9MQCYhI7DU+f3gFA=
|
||||
github.com/sassoftware/go-rpmutils v0.3.0/go.mod h1:hM9wdxFsjUFR/tJ6SMsLrJuChcucCa0DsCzE9RMfwMo=
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ=
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
|
||||
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||
github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d h1:RQqyEogx5J6wPdoxqL132b100j8KjcVHO1c0KLRoIhc=
|
||||
github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d/go.mod h1:PegD7EVqlN88z7TpCqH92hHP+GBpfomGCCnw1PFtNOA=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
@@ -732,8 +722,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
@@ -741,8 +731,8 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
|
||||
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||
github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
|
||||
github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@@ -787,8 +777,8 @@ github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/vbatts/go-mtree v0.5.3 h1:S/jYlfG8rZ+a0bhZd+RANXejy7M4Js8fq9U+XoWTd5w=
|
||||
@@ -812,8 +802,8 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@@ -825,6 +815,8 @@ github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1/go.mod h1:ly2RB
|
||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak=
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@@ -875,8 +867,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.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -966,8 +958,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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
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=
|
||||
@@ -1074,20 +1066,21 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.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.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
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=
|
||||
@@ -1100,8 +1093,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1377,8 +1370,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
||||
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
|
||||
modernc.org/sqlite v1.29.10 h1:3u93dz83myFnMilBGCOLbr+HjklS6+5rJLx4q86RDAg=
|
||||
modernc.org/sqlite v1.29.10/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA=
|
||||
modernc.org/sqlite v1.29.8 h1:nGKglNx9K5v0As+zF0/Gcl1kMkmaU1XynYyq92PbsC8=
|
||||
modernc.org/sqlite v1.29.8/go.mod h1:lQPm27iqa4UNZpmr4Aor0MH0HkCLbt1huYDfWylLZFk=
|
||||
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=
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
package cmptest
|
||||
|
||||
import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func DefaultCommonOptions() []cmp.Option {
|
||||
return CommonOptions(nil, nil)
|
||||
}
|
||||
|
||||
func CommonOptions(licenseCmp LicenseComparer, locationCmp LocationComparer) []cmp.Option {
|
||||
if licenseCmp == nil {
|
||||
licenseCmp = DefaultLicenseComparer
|
||||
}
|
||||
|
||||
if locationCmp == nil {
|
||||
locationCmp = DefaultLocationComparer
|
||||
}
|
||||
|
||||
return []cmp.Option{
|
||||
cmpopts.IgnoreFields(pkg.Package{}, "id"), // note: ID is not deterministic for test purposes
|
||||
cmpopts.SortSlices(pkg.Less),
|
||||
cmpopts.SortSlices(DefaultRelationshipComparer),
|
||||
cmp.Comparer(
|
||||
func(x, y file.LocationSet) bool {
|
||||
xs := x.ToSlice()
|
||||
ys := y.ToSlice()
|
||||
|
||||
if len(xs) != len(ys) {
|
||||
return false
|
||||
}
|
||||
for i, xe := range xs {
|
||||
ye := ys[i]
|
||||
if !locationCmp(xe, ye) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
),
|
||||
cmp.Comparer(
|
||||
func(x, y pkg.LicenseSet) bool {
|
||||
xs := x.ToSlice()
|
||||
ys := y.ToSlice()
|
||||
|
||||
if len(xs) != len(ys) {
|
||||
return false
|
||||
}
|
||||
for i, xe := range xs {
|
||||
ye := ys[i]
|
||||
if !licenseCmp(xe, ye) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
),
|
||||
cmp.Comparer(
|
||||
locationCmp,
|
||||
),
|
||||
cmp.Comparer(
|
||||
licenseCmp,
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package cmptest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
// DiffReporter is a simple custom reporter that only records differences detected during comparison.
|
||||
type DiffReporter struct {
|
||||
path cmp.Path
|
||||
diffs []string
|
||||
}
|
||||
|
||||
func NewDiffReporter() DiffReporter {
|
||||
return DiffReporter{}
|
||||
}
|
||||
|
||||
func (r *DiffReporter) PushStep(ps cmp.PathStep) {
|
||||
r.path = append(r.path, ps)
|
||||
}
|
||||
|
||||
func (r *DiffReporter) Report(rs cmp.Result) {
|
||||
if !rs.Equal() {
|
||||
vx, vy := r.path.Last().Values()
|
||||
r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *DiffReporter) PopStep() {
|
||||
r.path = r.path[:len(r.path)-1]
|
||||
}
|
||||
|
||||
func (r *DiffReporter) String() string {
|
||||
return strings.Join(r.diffs, "\n")
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package cmptest
|
||||
|
||||
import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
type LicenseComparer func(x, y pkg.License) bool
|
||||
|
||||
func DefaultLicenseComparer(x, y pkg.License) bool {
|
||||
return cmp.Equal(x, y, cmp.Comparer(DefaultLocationComparer), cmp.Comparer(
|
||||
func(x, y file.LocationSet) bool {
|
||||
xs := x.ToSlice()
|
||||
ys := y.ToSlice()
|
||||
if len(xs) != len(ys) {
|
||||
return false
|
||||
}
|
||||
for i, xe := range xs {
|
||||
ye := ys[i]
|
||||
if !DefaultLocationComparer(xe, ye) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package cmptest
|
||||
|
||||
import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
|
||||
type LocationComparer func(x, y file.Location) bool
|
||||
|
||||
func DefaultLocationComparer(x, y file.Location) bool {
|
||||
return cmp.Equal(x.Coordinates, y.Coordinates) && cmp.Equal(x.AccessPath, y.AccessPath)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package cmptest
|
||||
|
||||
import (
|
||||
"github.com/sanity-io/litter"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
)
|
||||
|
||||
type RelationshipComparer func(x, y artifact.Relationship) bool
|
||||
|
||||
var relationshipStringer = litter.Options{
|
||||
Compact: true,
|
||||
StripPackageNames: false,
|
||||
HidePrivateFields: true, // we want to ignore package IDs
|
||||
HideZeroValues: true,
|
||||
StrictGo: true,
|
||||
//FieldExclusions: ... // these can be added for future values that need to be ignored
|
||||
//FieldFilter: ...
|
||||
}
|
||||
|
||||
func DefaultRelationshipComparer(x, y artifact.Relationship) bool {
|
||||
// we just need a stable sort, the ordering does not need to be sensible
|
||||
xStr := relationshipStringer.Sdump(x)
|
||||
yStr := relationshipStringer.Sdump(y)
|
||||
return xStr < yStr
|
||||
}
|
||||
@@ -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.12"
|
||||
JSONSchemaVersion = "16.0.7"
|
||||
)
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/relationship"
|
||||
"github.com/anchore/syft/internal/sbomsync"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
func NewDependencyRelationships(resolver file.Resolver, accessor sbomsync.Accessor) []artifact.Relationship {
|
||||
// TODO: consider library format (e.g. ELF, Mach-O, PE) for the meantime assume all binaries are homogeneous format
|
||||
// start with building new package-to-package relationships for executables-to-executables
|
||||
// each relationship must be unique, store in a map[id]map[id]relationship to avoid duplicates
|
||||
// 1 & 2... build an index of all shared libraries and their owning packages to search against
|
||||
index := newShareLibIndex(resolver, accessor)
|
||||
|
||||
// 3. craft package-to-package relationships for each binary that represent shared library dependencies
|
||||
//note: we only care about package-to-package relationships
|
||||
var relIndex *relationship.Index
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
relIndex = relationship.NewIndex(s.Relationships...)
|
||||
})
|
||||
|
||||
return generateRelationships(resolver, accessor, index, relIndex)
|
||||
}
|
||||
|
||||
func generateRelationships(resolver file.Resolver, accessor sbomsync.Accessor, index *sharedLibraryIndex, relIndex *relationship.Index) []artifact.Relationship {
|
||||
// read all existing dependencyOf relationships
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
for _, r := range s.Relationships {
|
||||
if r.Type != artifact.DependencyOfRelationship {
|
||||
continue
|
||||
}
|
||||
relIndex.Track(r)
|
||||
}
|
||||
})
|
||||
|
||||
// find all package-to-package relationships for shared library dependencies
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
for _, parentPkg := range s.Artifacts.Packages.Sorted(pkg.BinaryPkg) {
|
||||
for _, evidentLocation := range parentPkg.Locations.ToSlice() {
|
||||
if evidentLocation.Annotations[pkg.EvidenceAnnotationKey] != pkg.PrimaryEvidenceAnnotation {
|
||||
continue
|
||||
}
|
||||
|
||||
// find all libraries that this package depends on
|
||||
exec, ok := s.Artifacts.Executables[evidentLocation.Coordinates]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
populateRelationships(exec, parentPkg, resolver, relIndex, index)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return relIndex.NewRelationships()
|
||||
}
|
||||
|
||||
// PackagesToRemove returns a list of binary packages (resolved by the ELF cataloger) that should be removed from the SBOM
|
||||
// These packages are removed because they are already represented by a higher order packages in the SBOM.
|
||||
func PackagesToRemove(resolver file.Resolver, accessor sbomsync.Accessor) []artifact.ID {
|
||||
pkgsToDelete := make([]artifact.ID, 0)
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
// OTHER package type > ELF package type > Binary package type
|
||||
pkgsToDelete = append(pkgsToDelete, getBinaryPackagesToDelete(resolver, s)...)
|
||||
pkgsToDelete = append(pkgsToDelete, compareElfBinaryPackages(s)...)
|
||||
})
|
||||
return pkgsToDelete
|
||||
}
|
||||
|
||||
func compareElfBinaryPackages(s *sbom.SBOM) []artifact.ID {
|
||||
pkgsToDelete := make([]artifact.ID, 0)
|
||||
for _, elfPkg := range allElfPackages(s) {
|
||||
for _, loc := range onlyPrimaryEvidenceLocations(elfPkg) {
|
||||
for _, otherPkg := range s.Artifacts.Packages.PackagesByPath(loc.RealPath) {
|
||||
// we only care about comparing binary packages to each other (not other types)
|
||||
if otherPkg.Type != pkg.BinaryPkg {
|
||||
continue
|
||||
}
|
||||
if !isElfPackage(otherPkg) {
|
||||
pkgsToDelete = append(pkgsToDelete, otherPkg.ID())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pkgsToDelete
|
||||
}
|
||||
|
||||
func onlyPrimaryEvidenceLocations(p pkg.Package) []file.Location {
|
||||
var locs []file.Location
|
||||
for _, loc := range p.Locations.ToSlice() {
|
||||
if loc.Annotations[pkg.EvidenceAnnotationKey] != pkg.PrimaryEvidenceAnnotation {
|
||||
continue
|
||||
}
|
||||
locs = append(locs, loc)
|
||||
}
|
||||
|
||||
return locs
|
||||
}
|
||||
|
||||
func allElfPackages(s *sbom.SBOM) []pkg.Package {
|
||||
var elfPkgs []pkg.Package
|
||||
for _, p := range s.Artifacts.Packages.Sorted(pkg.BinaryPkg) {
|
||||
if !isElfPackage(p) {
|
||||
continue
|
||||
}
|
||||
elfPkgs = append(elfPkgs, p)
|
||||
}
|
||||
return elfPkgs
|
||||
}
|
||||
|
||||
func isElfPackage(p pkg.Package) bool {
|
||||
_, ok := p.Metadata.(pkg.ELFBinaryPackageNoteJSONPayload)
|
||||
return ok
|
||||
}
|
||||
|
||||
func getBinaryPackagesToDelete(resolver file.Resolver, s *sbom.SBOM) []artifact.ID {
|
||||
pkgsToDelete := make([]artifact.ID, 0)
|
||||
for p := range s.Artifacts.Packages.Enumerate() {
|
||||
if p.Type == pkg.BinaryPkg {
|
||||
continue
|
||||
}
|
||||
fileOwner, ok := p.Metadata.(pkg.FileOwner)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
ownedFiles := fileOwner.OwnedFiles()
|
||||
locations, err := resolver.FilesByPath(ownedFiles...)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Trace("unable to find path for owned file")
|
||||
continue
|
||||
}
|
||||
for _, loc := range locations {
|
||||
for _, pathPkg := range s.Artifacts.Packages.PackagesByPath(loc.RealPath) {
|
||||
if pathPkg.Type == pkg.BinaryPkg {
|
||||
pkgsToDelete = append(pkgsToDelete, pathPkg.ID())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pkgsToDelete
|
||||
}
|
||||
|
||||
func populateRelationships(exec file.Executable, parentPkg pkg.Package, resolver file.Resolver, relIndex *relationship.Index, index *sharedLibraryIndex) {
|
||||
for _, libReference := range exec.ImportedLibraries {
|
||||
// for each library reference, check s.Artifacts.Packages.Sorted(pkg.BinaryPkg) for a binary package that represents that library
|
||||
// if found, create a relationship between the parent package and the library package
|
||||
// if not found do nothing.
|
||||
// note: we only care about package-to-package relationships
|
||||
|
||||
// find the basename of the library
|
||||
libBasename := path.Base(libReference)
|
||||
libLocations, err := resolver.FilesByGlob("**/" + libBasename)
|
||||
if err != nil {
|
||||
log.WithFields("lib", libReference, "error", err).Trace("unable to resolve library basename")
|
||||
continue
|
||||
}
|
||||
|
||||
for _, loc := range libLocations {
|
||||
// are you in our index?
|
||||
realBaseName := path.Base(loc.RealPath)
|
||||
pkgCollection := index.owningLibraryPackage(realBaseName)
|
||||
if pkgCollection.PackageCount() < 1 {
|
||||
relIndex.Add(
|
||||
artifact.Relationship{
|
||||
From: loc.Coordinates,
|
||||
To: parentPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
)
|
||||
}
|
||||
for _, p := range pkgCollection.Sorted() {
|
||||
relIndex.Add(
|
||||
artifact.Relationship{
|
||||
From: p,
|
||||
To: parentPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
|
||||
"github.com/anchore/syft/internal/sbomsync"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
func TestPackagesToRemove(t *testing.T) {
|
||||
glibcCoordinate := file.NewCoordinates("/usr/lib64/libc.so.6", "")
|
||||
glibCPackage := pkg.Package{
|
||||
Name: "glibc",
|
||||
Version: "2.28-236.el8_9.12",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation(glibcCoordinate.RealPath),
|
||||
),
|
||||
Type: pkg.RpmPkg,
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Files: []pkg.RpmFileRecord{
|
||||
{
|
||||
Path: glibcCoordinate.RealPath,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
glibCPackage.SetID()
|
||||
|
||||
glibCBinaryELFPackage := pkg.Package{
|
||||
Name: "glibc",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation(glibcCoordinate.RealPath).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
Type: pkg.BinaryPkg,
|
||||
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
|
||||
Type: "testfixture",
|
||||
Vendor: "syft",
|
||||
System: "syftsys",
|
||||
SourceRepo: "https://github.com/someone/somewhere.git",
|
||||
Commit: "5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb",
|
||||
},
|
||||
}
|
||||
glibCBinaryELFPackage.SetID()
|
||||
|
||||
glibCBinaryClassifierPackage := pkg.Package{
|
||||
Name: "glibc",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation(glibcCoordinate.RealPath).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation),
|
||||
),
|
||||
Type: pkg.BinaryPkg,
|
||||
Metadata: pkg.BinarySignature{},
|
||||
}
|
||||
glibCBinaryClassifierPackage.SetID()
|
||||
|
||||
libCBinaryClassifierPackage := pkg.Package{
|
||||
Name: "libc",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation(glibcCoordinate.RealPath).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
Type: pkg.BinaryPkg,
|
||||
Metadata: pkg.BinarySignature{},
|
||||
}
|
||||
libCBinaryClassifierPackage.SetID()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
resolver file.Resolver
|
||||
accessor sbomsync.Accessor
|
||||
want []artifact.ID
|
||||
}{
|
||||
{
|
||||
name: "remove packages that are overlapping rpm --> binary",
|
||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
||||
accessor: newAccessor([]pkg.Package{glibCPackage, glibCBinaryELFPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||
want: []artifact.ID{glibCBinaryELFPackage.ID()},
|
||||
},
|
||||
{
|
||||
name: "remove no packages when there is a single binary package",
|
||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
||||
accessor: newAccessor([]pkg.Package{glibCBinaryELFPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||
want: []artifact.ID{},
|
||||
},
|
||||
{
|
||||
name: "remove packages when there is a single binary package and a classifier package",
|
||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
||||
accessor: newAccessor([]pkg.Package{glibCBinaryELFPackage, glibCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||
want: []artifact.ID{glibCBinaryClassifierPackage.ID()},
|
||||
},
|
||||
{
|
||||
name: "ensure we're considering ELF packages, not just binary packages (supporting evidence)",
|
||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
||||
accessor: newAccessor([]pkg.Package{glibCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||
want: []artifact.ID{},
|
||||
},
|
||||
{
|
||||
name: "ensure we're considering ELF packages, not just binary packages (primary evidence)",
|
||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
||||
accessor: newAccessor([]pkg.Package{libCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||
want: []artifact.ID{},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
pkgsToDelete := PackagesToRemove(tt.resolver, tt.accessor)
|
||||
if diff := cmp.Diff(tt.want, pkgsToDelete); diff != "" {
|
||||
t.Errorf("unexpected packages to delete (-want, +got): %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDependencyRelationships(t *testing.T) {
|
||||
// coordinates for the files under test
|
||||
glibcCoordinate := file.NewCoordinates("/usr/lib64/libc.so.6", "")
|
||||
secondGlibcCoordinate := file.NewCoordinates("/usr/local/lib64/libc.so.6", "")
|
||||
nestedLibCoordinate := file.NewCoordinates("/usr/local/bin/elftests/elfbinwithnestedlib/bin/elfbinwithnestedlib", "")
|
||||
parallelLibCoordinate := file.NewCoordinates("/usr/local/bin/elftests/elfbinwithsisterlib/bin/elfwithparallellibbin1", "")
|
||||
|
||||
// rpm package that was discovered in linked section of the ELF binary package
|
||||
glibCPackage := pkg.Package{
|
||||
Name: "glibc",
|
||||
Version: "2.28-236.el8_9.12",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation(glibcCoordinate.RealPath),
|
||||
file.NewLocation("some/other/path"),
|
||||
),
|
||||
Type: pkg.RpmPkg,
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Files: []pkg.RpmFileRecord{
|
||||
{
|
||||
Path: glibcCoordinate.RealPath,
|
||||
},
|
||||
{
|
||||
Path: "some/other/path",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
glibCPackage.SetID()
|
||||
|
||||
// second rpm package that could be discovered in linked section of the ELF binary package (same base path as above)
|
||||
glibCustomPackage := pkg.Package{
|
||||
Name: "glibc",
|
||||
Version: "2.28-236.el8_9.12",
|
||||
Locations: file.NewLocationSet(file.NewLocation(secondGlibcCoordinate.RealPath)),
|
||||
Type: pkg.RpmPkg,
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Files: []pkg.RpmFileRecord{
|
||||
{
|
||||
Path: secondGlibcCoordinate.RealPath,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
glibCustomPackage.SetID()
|
||||
|
||||
// binary package that is an executable that can link against above rpm packages
|
||||
syftTestFixturePackage := pkg.Package{
|
||||
Name: "syfttestfixture",
|
||||
Version: "0.01",
|
||||
PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
|
||||
FoundBy: "",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation(nestedLibCoordinate.RealPath).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
file.NewLocation(parallelLibCoordinate.RealPath).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation),
|
||||
),
|
||||
Language: "",
|
||||
Type: pkg.BinaryPkg,
|
||||
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
|
||||
Type: "testfixture",
|
||||
Vendor: "syft",
|
||||
System: "syftsys",
|
||||
SourceRepo: "https://github.com/someone/somewhere.git",
|
||||
Commit: "5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb",
|
||||
},
|
||||
}
|
||||
syftTestFixturePackage.SetID()
|
||||
|
||||
// dummy executable representation of glibc
|
||||
glibcExecutable := file.Executable{
|
||||
Format: "elf",
|
||||
HasExports: true,
|
||||
HasEntrypoint: true,
|
||||
ImportedLibraries: []string{},
|
||||
}
|
||||
|
||||
// executable representation of the syftTestFixturePackage
|
||||
syftTestFixtureExecutable := file.Executable{
|
||||
Format: "elf",
|
||||
HasExports: true,
|
||||
HasEntrypoint: true,
|
||||
ImportedLibraries: []string{
|
||||
path.Base(glibcCoordinate.RealPath),
|
||||
},
|
||||
}
|
||||
|
||||
// second executable representation that has no parent package
|
||||
syftTestFixtureExecutable2 := file.Executable{
|
||||
Format: "elf",
|
||||
HasExports: true,
|
||||
HasEntrypoint: true,
|
||||
ImportedLibraries: []string{
|
||||
// this should not be a relationship because it is not a coordinate
|
||||
"foo.so.6",
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
resolver file.Resolver
|
||||
coordinateIndex map[file.Coordinates]file.Executable
|
||||
packages []pkg.Package
|
||||
prexistingRelationships []artifact.Relationship
|
||||
want []artifact.Relationship
|
||||
}{
|
||||
{
|
||||
name: "blank sbom and accessor returns empty relationships",
|
||||
resolver: nil,
|
||||
coordinateIndex: map[file.Coordinates]file.Executable{},
|
||||
packages: []pkg.Package{},
|
||||
},
|
||||
{
|
||||
name: "given a package that imports glibc, expect a relationship between the two packages when the package is an executable",
|
||||
resolver: file.NewMockResolverForPaths(
|
||||
glibcCoordinate.RealPath,
|
||||
nestedLibCoordinate.RealPath,
|
||||
parallelLibCoordinate.RealPath,
|
||||
),
|
||||
// path -> executable (above mock resolver needs to be able to resolve to paths in this map)
|
||||
coordinateIndex: map[file.Coordinates]file.Executable{
|
||||
glibcCoordinate: glibcExecutable,
|
||||
nestedLibCoordinate: syftTestFixtureExecutable,
|
||||
parallelLibCoordinate: syftTestFixtureExecutable2,
|
||||
},
|
||||
packages: []pkg.Package{glibCPackage, syftTestFixturePackage},
|
||||
want: []artifact.Relationship{
|
||||
{
|
||||
From: glibCPackage,
|
||||
To: syftTestFixturePackage,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "given an executable maps to one base path represented by two RPM we make two relationships",
|
||||
resolver: file.NewMockResolverForPaths(
|
||||
glibcCoordinate.RealPath,
|
||||
secondGlibcCoordinate.RealPath,
|
||||
nestedLibCoordinate.RealPath,
|
||||
parallelLibCoordinate.RealPath,
|
||||
),
|
||||
coordinateIndex: map[file.Coordinates]file.Executable{
|
||||
glibcCoordinate: glibcExecutable,
|
||||
secondGlibcCoordinate: glibcExecutable,
|
||||
nestedLibCoordinate: syftTestFixtureExecutable,
|
||||
parallelLibCoordinate: syftTestFixtureExecutable2,
|
||||
},
|
||||
packages: []pkg.Package{glibCPackage, glibCustomPackage, syftTestFixturePackage},
|
||||
want: []artifact.Relationship{
|
||||
{
|
||||
From: glibCPackage,
|
||||
To: syftTestFixturePackage,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
{
|
||||
From: glibCustomPackage,
|
||||
To: syftTestFixturePackage,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "given some dependency relationships already exist, expect no duplicate relationships to be created",
|
||||
resolver: file.NewMockResolverForPaths(
|
||||
glibcCoordinate.RealPath,
|
||||
nestedLibCoordinate.RealPath,
|
||||
parallelLibCoordinate.RealPath,
|
||||
),
|
||||
coordinateIndex: map[file.Coordinates]file.Executable{
|
||||
glibcCoordinate: glibcExecutable,
|
||||
nestedLibCoordinate: syftTestFixtureExecutable,
|
||||
parallelLibCoordinate: syftTestFixtureExecutable2,
|
||||
},
|
||||
packages: []pkg.Package{glibCPackage, glibCustomPackage, syftTestFixturePackage},
|
||||
prexistingRelationships: []artifact.Relationship{
|
||||
{
|
||||
From: glibCPackage,
|
||||
To: syftTestFixturePackage,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "given a package that imports a library that is not tracked by the resolver, expect no relationships to be created",
|
||||
resolver: file.NewMockResolverForPaths(),
|
||||
coordinateIndex: map[file.Coordinates]file.Executable{
|
||||
glibcCoordinate: glibcExecutable,
|
||||
nestedLibCoordinate: syftTestFixtureExecutable,
|
||||
parallelLibCoordinate: syftTestFixtureExecutable2,
|
||||
},
|
||||
packages: []pkg.Package{glibCPackage, syftTestFixturePackage},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
accessor := newAccessor(tt.packages, tt.coordinateIndex, tt.prexistingRelationships)
|
||||
// given a resolver that knows about the paths of the packages and executables,
|
||||
// and given an SBOM accessor that knows about the packages and executables,
|
||||
// we should be able to create a set of relationships between the packages and executables
|
||||
relationships := NewDependencyRelationships(tt.resolver, accessor)
|
||||
if diff := relationshipComparer(tt.want, relationships); diff != "" {
|
||||
t.Errorf("unexpected relationships (-want, +got): %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func relationshipComparer(x, y []artifact.Relationship) string {
|
||||
return cmp.Diff(x, y, cmpopts.IgnoreUnexported(
|
||||
pkg.Package{},
|
||||
artifact.Relationship{},
|
||||
file.LocationSet{},
|
||||
pkg.LicenseSet{},
|
||||
))
|
||||
}
|
||||
|
||||
func newAccessor(pkgs []pkg.Package, coordinateIndex map[file.Coordinates]file.Executable, preexistingRelationships []artifact.Relationship) sbomsync.Accessor {
|
||||
sb := sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
Packages: pkg.NewCollection(),
|
||||
},
|
||||
}
|
||||
|
||||
builder := sbomsync.NewBuilder(&sb)
|
||||
builder.AddPackages(pkgs...)
|
||||
|
||||
accessor := builder.(sbomsync.Accessor)
|
||||
accessor.WriteToSBOM(func(s *sbom.SBOM) {
|
||||
s.Artifacts.Executables = coordinateIndex
|
||||
if preexistingRelationships != nil {
|
||||
s.Relationships = preexistingRelationships
|
||||
}
|
||||
})
|
||||
return accessor
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/sbomsync"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
type sharedLibraryIndex struct {
|
||||
libLocationsByBasename map[string]file.CoordinateSet
|
||||
allLibLocations file.CoordinateSet
|
||||
packagesByLibraryPath map[file.Coordinates]*pkg.Collection
|
||||
}
|
||||
|
||||
func newShareLibIndex(resolver file.Resolver, accessor sbomsync.Accessor) *sharedLibraryIndex {
|
||||
s := &sharedLibraryIndex{
|
||||
libLocationsByBasename: make(map[string]file.CoordinateSet),
|
||||
allLibLocations: file.NewCoordinateSet(),
|
||||
packagesByLibraryPath: make(map[file.Coordinates]*pkg.Collection),
|
||||
}
|
||||
|
||||
s.build(resolver, accessor)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (i *sharedLibraryIndex) build(resolver file.Resolver, accessor sbomsync.Accessor) {
|
||||
// 1. map out all locations that provide libraries (indexed by the basename)
|
||||
i.libLocationsByBasename, i.allLibLocations = locationsThatProvideLibraries(accessor)
|
||||
|
||||
// 2. for each library path, find all packages that claim ownership of the library
|
||||
i.packagesByLibraryPath = packagesWithLibraryOwnership(resolver, accessor, i.allLibLocations)
|
||||
}
|
||||
|
||||
func (i *sharedLibraryIndex) owningLibraryPackage(libraryBasename string) *pkg.Collection {
|
||||
// find all packages that own a library by its basename
|
||||
collection := pkg.NewCollection()
|
||||
if set, ok := i.libLocationsByBasename[libraryBasename]; ok {
|
||||
for _, coord := range set.ToSlice() {
|
||||
if pkgSet, ok := i.packagesByLibraryPath[coord]; ok {
|
||||
toAdd := pkgSet.Sorted()
|
||||
collection.Add(toAdd...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return collection
|
||||
}
|
||||
|
||||
func locationsThatProvideLibraries(accessor sbomsync.Accessor) (map[string]file.CoordinateSet, file.CoordinateSet) {
|
||||
// map out all locations that provide libraries (indexed by the basename)
|
||||
libLocationsByBasename := make(map[string]file.CoordinateSet)
|
||||
allLibLocations := file.NewCoordinateSet()
|
||||
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
// PROBLEM: this does not consider all symlinks to real paths that are libraries
|
||||
for coord, f := range s.Artifacts.Executables {
|
||||
if !f.HasExports {
|
||||
continue
|
||||
}
|
||||
|
||||
basename := path.Base(coord.RealPath)
|
||||
set := libLocationsByBasename[basename]
|
||||
set.Add(coord)
|
||||
allLibLocations.Add(coord)
|
||||
libLocationsByBasename[basename] = set
|
||||
}
|
||||
})
|
||||
|
||||
return libLocationsByBasename, allLibLocations
|
||||
}
|
||||
func packagesWithLibraryOwnership(resolver file.Resolver, accessor sbomsync.Accessor, allLibLocations file.CoordinateSet) map[file.Coordinates]*pkg.Collection {
|
||||
// map out all packages that claim ownership of a library at a specific path
|
||||
packagesByLibraryPath := make(map[file.Coordinates]*pkg.Collection)
|
||||
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
for _, p := range s.Artifacts.Packages.Sorted() {
|
||||
var ownedFilePaths []string
|
||||
if p.Type == pkg.BinaryPkg {
|
||||
for _, loc := range p.Locations.ToSlice() {
|
||||
ownedFilePaths = append(ownedFilePaths, loc.Path())
|
||||
}
|
||||
} else {
|
||||
fileOwner, ok := p.Metadata.(pkg.FileOwner)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
ownedFilePaths = fileOwner.OwnedFiles()
|
||||
}
|
||||
|
||||
packagesByLibraryPath = populatePackagesByLibraryPath(resolver, allLibLocations, packagesByLibraryPath, p, ownedFilePaths)
|
||||
}
|
||||
})
|
||||
|
||||
return packagesByLibraryPath
|
||||
}
|
||||
|
||||
func populatePackagesByLibraryPath(
|
||||
resolver file.Resolver,
|
||||
allLibLocations file.CoordinateSet,
|
||||
packagesByLibraryPath map[file.Coordinates]*pkg.Collection,
|
||||
p pkg.Package,
|
||||
ownedFilePaths []string,
|
||||
) map[file.Coordinates]*pkg.Collection {
|
||||
for _, pth := range ownedFilePaths {
|
||||
ownedLocation, err := resolver.FilesByPath(pth)
|
||||
if err != nil {
|
||||
log.WithFields("error", err, "path", pth).Trace("unable to find path for owned file")
|
||||
continue
|
||||
}
|
||||
|
||||
for _, loc := range ownedLocation {
|
||||
// if the location is a library, add the package to the set of packages that own the library
|
||||
if !allLibLocations.Contains(loc.Coordinates) {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := packagesByLibraryPath[loc.Coordinates]; !ok {
|
||||
packagesByLibraryPath[loc.Coordinates] = pkg.NewCollection()
|
||||
}
|
||||
|
||||
// we have a library path, add the package to the set of packages that own the library
|
||||
packagesByLibraryPath[loc.Coordinates].Add(p)
|
||||
}
|
||||
}
|
||||
return packagesByLibraryPath
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func Test_newShareLibIndex(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resolver file.Resolver
|
||||
coordinateIndex map[file.Coordinates]file.Executable
|
||||
packages []pkg.Package
|
||||
prexistingRelationships []artifact.Relationship
|
||||
}{
|
||||
{
|
||||
name: "constructor",
|
||||
resolver: file.NewMockResolverForPaths(),
|
||||
coordinateIndex: map[file.Coordinates]file.Executable{},
|
||||
packages: []pkg.Package{},
|
||||
prexistingRelationships: []artifact.Relationship{},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
accessor := newAccessor(tt.packages, tt.coordinateIndex, tt.prexistingRelationships)
|
||||
sharedLibraryIndex := newShareLibIndex(tt.resolver, accessor)
|
||||
if sharedLibraryIndex == nil {
|
||||
t.Errorf("newShareLibIndex() = %v, want non-nil", sharedLibraryIndex)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_sharedLibraryIndex_build(t *testing.T) {
|
||||
glibcCoordinate := file.NewCoordinates("/usr/lib64/libc.so.6", "")
|
||||
secondGlibcCoordinate := file.NewCoordinates("/usr/local/lib64/libc.so.6", "")
|
||||
glibcExecutable := file.Executable{
|
||||
Format: "elf",
|
||||
HasExports: true,
|
||||
HasEntrypoint: true,
|
||||
ImportedLibraries: []string{
|
||||
path.Base(glibcCoordinate.RealPath),
|
||||
path.Base(secondGlibcCoordinate.RealPath),
|
||||
},
|
||||
}
|
||||
glibCPackage := pkg.Package{
|
||||
Name: "glibc",
|
||||
Version: "2.28-236.el8_9.12",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation(glibcCoordinate.RealPath),
|
||||
file.NewLocation("some/other/path"),
|
||||
),
|
||||
Type: pkg.RpmPkg,
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Files: []pkg.RpmFileRecord{
|
||||
{
|
||||
Path: glibcCoordinate.RealPath,
|
||||
},
|
||||
{
|
||||
Path: "some/other/path",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
resolver file.Resolver
|
||||
coordinateIndex map[file.Coordinates]file.Executable
|
||||
packages []pkg.Package
|
||||
prexistingRelationships []artifact.Relationship
|
||||
}{
|
||||
{
|
||||
name: "build with locations and packages",
|
||||
resolver: file.NewMockResolverForPaths([]string{
|
||||
glibcCoordinate.RealPath,
|
||||
secondGlibcCoordinate.RealPath,
|
||||
}...),
|
||||
coordinateIndex: map[file.Coordinates]file.Executable{
|
||||
glibcCoordinate: glibcExecutable,
|
||||
secondGlibcCoordinate: glibcExecutable,
|
||||
},
|
||||
packages: []pkg.Package{
|
||||
glibCPackage,
|
||||
},
|
||||
prexistingRelationships: []artifact.Relationship{},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
accessor := newAccessor(tt.packages, tt.coordinateIndex, tt.prexistingRelationships)
|
||||
sharedLibraryIndex := newShareLibIndex(tt.resolver, accessor)
|
||||
sharedLibraryIndex.build(tt.resolver, accessor)
|
||||
pkgs := sharedLibraryIndex.owningLibraryPackage(path.Base(glibcCoordinate.RealPath))
|
||||
if pkgs.PackageCount() < 1 {
|
||||
t.Errorf("owningLibraryPackage() = %v, want non-empty", pkgs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
../../../../syft/pkg/cataloger/binary/test-fixtures/elf-test-fixtures
|
||||
@@ -32,7 +32,7 @@ type ownershipByFilesMetadata struct {
|
||||
Files []string `json:"files"`
|
||||
}
|
||||
|
||||
func ByFileOwnershipOverlapWorker(accessor sbomsync.Accessor) {
|
||||
func byFileOwnershipOverlapWorker(accessor sbomsync.Accessor) {
|
||||
var relationships []artifact.Relationship
|
||||
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
@@ -58,19 +58,9 @@ func byFileOwnershipOverlap(catalog *pkg.Collection) []artifact.Relationship {
|
||||
parent := catalog.Package(parentID) // TODO: this is potentially expensive
|
||||
child := catalog.Package(childID) // TODO: this is potentially expensive
|
||||
|
||||
if parent == nil {
|
||||
log.Tracef("parent package not found: %v", parentID)
|
||||
continue
|
||||
}
|
||||
|
||||
if child == nil {
|
||||
log.Tracef("child package not found: %v", childID)
|
||||
continue
|
||||
}
|
||||
|
||||
edges = append(edges, artifact.Relationship{
|
||||
From: *parent,
|
||||
To: *child,
|
||||
From: parent,
|
||||
To: child,
|
||||
Type: artifact.OwnershipByFileOverlapRelationship,
|
||||
Data: ownershipByFilesMetadata{
|
||||
Files: fs,
|
||||
|
||||
@@ -3,10 +3,8 @@ package relationship
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/internal/cmptest"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -145,9 +143,10 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
|
||||
assert.Len(t, relationships, len(expectedRelations))
|
||||
for idx, expectedRelationship := range expectedRelations {
|
||||
actualRelationship := relationships[idx]
|
||||
if d := cmp.Diff(expectedRelationship, actualRelationship, cmptest.DefaultCommonOptions()...); d != "" {
|
||||
t.Errorf("unexpected relationship (-want, +got): %s", d)
|
||||
}
|
||||
assert.Equal(t, expectedRelationship.From.ID(), actualRelationship.From.ID())
|
||||
assert.Equal(t, expectedRelationship.To.ID(), actualRelationship.To.ID())
|
||||
assert.Equal(t, expectedRelationship.Type, actualRelationship.Type)
|
||||
assert.Equal(t, expectedRelationship.Data, actualRelationship.Data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func EvidentBy(catalog *pkg.Collection) []artifact.Relationship {
|
||||
func evidentBy(catalog *pkg.Collection) []artifact.Relationship {
|
||||
var edges []artifact.Relationship
|
||||
for _, p := range catalog.Sorted() {
|
||||
for _, l := range p.Locations.ToSlice() {
|
||||
|
||||
@@ -76,7 +76,7 @@ func TestRelationshipsEvidentBy(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
actual := EvidentBy(tt.catalog)
|
||||
actual := evidentBy(tt.catalog)
|
||||
require.Len(t, actual, len(tt.want))
|
||||
for i := range actual {
|
||||
assert.Equal(t, tt.want[i].From.ID(), actual[i].From.ID(), "from mismatch at index %d", i)
|
||||
|
||||
@@ -23,7 +23,7 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func ExcludeBinariesByFileOwnershipOverlap(accessor sbomsync.Accessor) {
|
||||
func excludeBinariesByFileOwnershipOverlap(accessor sbomsync.Accessor) {
|
||||
accessor.WriteToSBOM(func(s *sbom.SBOM) {
|
||||
for _, r := range s.Relationships {
|
||||
if excludeBinaryByFileOwnershipOverlap(r, s.Artifacts.Packages) {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package relationship
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/internal/sbomsync"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/cataloging"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
func Finalize(builder sbomsync.Builder, cfg cataloging.RelationshipsConfig, src artifact.Identifiable) {
|
||||
accessor := builder.(sbomsync.Accessor)
|
||||
|
||||
// add relationships showing packages that are evident by a file which is owned by another package (package-to-package)
|
||||
if cfg.PackageFileOwnershipOverlap {
|
||||
byFileOwnershipOverlapWorker(accessor)
|
||||
}
|
||||
|
||||
// conditionally remove binary packages based on file ownership overlap relationships found
|
||||
// https://github.com/anchore/syft/issues/931
|
||||
if cfg.ExcludeBinaryPackagesWithFileOwnershipOverlap {
|
||||
excludeBinariesByFileOwnershipOverlap(accessor)
|
||||
}
|
||||
|
||||
// add source "contains package" relationship (source-to-package)
|
||||
var sourceRelationships []artifact.Relationship
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
sourceRelationships = toSource(src, s.Artifacts.Packages)
|
||||
})
|
||||
builder.AddRelationships(sourceRelationships...)
|
||||
|
||||
// add evident-by relationships (package-to-file)
|
||||
var evidentByRelationships []artifact.Relationship
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
evidentByRelationships = evidentBy(s.Artifacts.Packages)
|
||||
})
|
||||
builder.AddRelationships(evidentByRelationships...)
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package relationship
|
||||
|
||||
import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
)
|
||||
|
||||
type Index struct {
|
||||
typesByFromTo map[artifact.ID]map[artifact.ID]*strset.Set
|
||||
existing []artifact.Relationship
|
||||
additional []artifact.Relationship
|
||||
}
|
||||
|
||||
func NewIndex(existing ...artifact.Relationship) *Index {
|
||||
r := &Index{
|
||||
typesByFromTo: make(map[artifact.ID]map[artifact.ID]*strset.Set),
|
||||
}
|
||||
r.TrackAll(existing...)
|
||||
return r
|
||||
}
|
||||
|
||||
func (i *Index) track(r artifact.Relationship) bool {
|
||||
fromID := r.From.ID()
|
||||
if _, ok := i.typesByFromTo[fromID]; !ok {
|
||||
i.typesByFromTo[fromID] = make(map[artifact.ID]*strset.Set)
|
||||
}
|
||||
|
||||
toID := r.To.ID()
|
||||
if _, ok := i.typesByFromTo[fromID][toID]; !ok {
|
||||
i.typesByFromTo[fromID][toID] = strset.New()
|
||||
}
|
||||
|
||||
var exists bool
|
||||
if i.typesByFromTo[fromID][toID].Has(string(r.Type)) {
|
||||
exists = true
|
||||
}
|
||||
|
||||
i.typesByFromTo[fromID][toID].Add(string(r.Type))
|
||||
|
||||
return !exists
|
||||
}
|
||||
|
||||
// Track this relationship as "exists" in the index (this is used to prevent duplicate relationships from being added).
|
||||
// returns true if the relationship is new to the index, false otherwise.
|
||||
func (i *Index) Track(r artifact.Relationship) bool {
|
||||
unique := i.track(r)
|
||||
if unique {
|
||||
i.existing = append(i.existing, r)
|
||||
}
|
||||
return unique
|
||||
}
|
||||
|
||||
// Add a new relationship to the index, returning true if the relationship is new to the index, false otherwise (thus is a duplicate).
|
||||
func (i *Index) Add(r artifact.Relationship) bool {
|
||||
if i.track(r) {
|
||||
i.additional = append(i.additional, r)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *Index) TrackAll(rs ...artifact.Relationship) {
|
||||
for _, r := range rs {
|
||||
i.Track(r)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Index) AddAll(rs ...artifact.Relationship) {
|
||||
for _, r := range rs {
|
||||
i.Add(r)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Index) NewRelationships() []artifact.Relationship {
|
||||
return i.additional
|
||||
}
|
||||
|
||||
func (i *Index) ExistingRelationships() []artifact.Relationship {
|
||||
return i.existing
|
||||
}
|
||||
|
||||
func (i *Index) AllUniqueRelationships() []artifact.Relationship {
|
||||
var all []artifact.Relationship
|
||||
all = append(all, i.existing...)
|
||||
all = append(all, i.additional...)
|
||||
return all
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
package relationship
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
)
|
||||
|
||||
func Test_newRelationshipIndex(t *testing.T) {
|
||||
from := fakeIdentifiable{id: "from"}
|
||||
to := fakeIdentifiable{id: "to"}
|
||||
tests := []struct {
|
||||
name string
|
||||
given []artifact.Relationship
|
||||
track []artifact.Relationship
|
||||
add []artifact.Relationship
|
||||
wantExisting []string
|
||||
wantAdditional []string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
},
|
||||
{
|
||||
name: "tracks existing relationships",
|
||||
given: []artifact.Relationship{
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
},
|
||||
wantExisting: []string{"from [evident-by] to"},
|
||||
},
|
||||
{
|
||||
name: "deduplicate tracked relationships",
|
||||
given: []artifact.Relationship{
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
},
|
||||
track: []artifact.Relationship{
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
},
|
||||
wantExisting: []string{"from [evident-by] to"},
|
||||
},
|
||||
{
|
||||
name: "deduplicate any input relationships",
|
||||
given: []artifact.Relationship{
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
},
|
||||
track: []artifact.Relationship{
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
},
|
||||
add: []artifact.Relationship{
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
},
|
||||
wantExisting: []string{"from [evident-by] to"},
|
||||
},
|
||||
{
|
||||
name: "deduplicate any added relationships",
|
||||
add: []artifact.Relationship{
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
},
|
||||
wantAdditional: []string{"from [evident-by] to"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
idx := NewIndex(tt.given...)
|
||||
idx.TrackAll(tt.track...)
|
||||
idx.AddAll(tt.add...)
|
||||
diffRelationships(t, tt.wantExisting, idx.existing)
|
||||
diffRelationships(t, tt.wantAdditional, idx.additional)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func diffRelationships(t *testing.T, expected []string, actual []artifact.Relationship) {
|
||||
if d := cmp.Diff(expected, stringRelationships(actual)); d != "" {
|
||||
t.Errorf("unexpected relationships (-want, +got): %s", d)
|
||||
}
|
||||
}
|
||||
|
||||
func stringRelationships(relationships []artifact.Relationship) []string {
|
||||
var result []string
|
||||
for _, r := range relationships {
|
||||
result = append(result, string(r.From.ID())+" ["+string(r.Type)+"] "+string(r.To.ID()))
|
||||
}
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
func Test_relationshipIndex_track(t *testing.T) {
|
||||
from := fakeIdentifiable{id: "from"}
|
||||
to := fakeIdentifiable{id: "to"}
|
||||
relationship := artifact.Relationship{From: from, To: to, Type: artifact.EvidentByRelationship}
|
||||
tests := []struct {
|
||||
name string
|
||||
existing []artifact.Relationship
|
||||
given artifact.Relationship
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "track returns true for a new relationship",
|
||||
existing: []artifact.Relationship{},
|
||||
given: relationship,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "track returns false for an existing relationship",
|
||||
existing: []artifact.Relationship{relationship},
|
||||
given: relationship,
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
i := NewIndex(tt.existing...)
|
||||
if got := i.Track(tt.given); got != tt.want {
|
||||
t.Errorf("track() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_relationshipIndex_add(t *testing.T) {
|
||||
from := fakeIdentifiable{id: "from"}
|
||||
to := fakeIdentifiable{id: "to"}
|
||||
relationship := artifact.Relationship{From: from, To: to, Type: artifact.EvidentByRelationship}
|
||||
tests := []struct {
|
||||
name string
|
||||
existing []artifact.Relationship
|
||||
given artifact.Relationship
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "add returns true for a new relationship",
|
||||
existing: []artifact.Relationship{},
|
||||
given: relationship,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "add returns false for an existing relationship",
|
||||
existing: []artifact.Relationship{relationship},
|
||||
given: relationship,
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
i := NewIndex(tt.existing...)
|
||||
if got := i.Add(tt.given); got != tt.want {
|
||||
t.Errorf("add() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type fakeIdentifiable struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (f fakeIdentifiable) ID() artifact.ID {
|
||||
return artifact.ID(f.id)
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func ToSource(src artifact.Identifiable, c *pkg.Collection) []artifact.Relationship {
|
||||
func toSource(src artifact.Identifiable, c *pkg.Collection) []artifact.Relationship {
|
||||
relationships := make([]artifact.Relationship, 0) // Should we pre-allocate this by giving catalog a Len() method?
|
||||
for p := range c.Enumerate() {
|
||||
relationships = append(relationships, artifact.Relationship{
|
||||
|
||||
@@ -20,8 +20,6 @@ type Builder interface {
|
||||
|
||||
AddPackages(...pkg.Package)
|
||||
|
||||
DeletePackages(...artifact.ID)
|
||||
|
||||
// edges
|
||||
|
||||
AddRelationships(...artifact.Relationship)
|
||||
@@ -38,22 +36,14 @@ type Accessor interface {
|
||||
}
|
||||
|
||||
type sbomBuilder struct {
|
||||
sbom *sbom.SBOM
|
||||
lock *sync.RWMutex
|
||||
onWrite []func(*sbom.SBOM)
|
||||
sbom *sbom.SBOM
|
||||
lock *sync.RWMutex
|
||||
}
|
||||
|
||||
func NewBuilder(s *sbom.SBOM, onWrite ...func(*sbom.SBOM)) Builder {
|
||||
func NewBuilder(s *sbom.SBOM) Builder {
|
||||
return &sbomBuilder{
|
||||
sbom: s,
|
||||
lock: &sync.RWMutex{},
|
||||
onWrite: onWrite,
|
||||
}
|
||||
}
|
||||
|
||||
func (b sbomBuilder) onWriteEvent() {
|
||||
for _, fn := range b.onWrite {
|
||||
fn(b.sbom)
|
||||
sbom: s,
|
||||
lock: &sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +52,6 @@ func (b sbomBuilder) WriteToSBOM(fn func(*sbom.SBOM)) {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
fn(b.sbom)
|
||||
b.onWriteEvent()
|
||||
}
|
||||
|
||||
func (b sbomBuilder) ReadFromSBOM(fn func(*sbom.SBOM)) {
|
||||
@@ -77,35 +66,6 @@ func (b sbomBuilder) AddPackages(p ...pkg.Package) {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sbom.Artifacts.Packages.Add(p...)
|
||||
b.onWriteEvent()
|
||||
}
|
||||
|
||||
func (b sbomBuilder) DeletePackages(ids ...artifact.ID) {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
deleted := make(map[artifact.ID]struct{})
|
||||
for _, id := range ids {
|
||||
b.sbom.Artifacts.Packages.Delete(id)
|
||||
deleted[id] = struct{}{}
|
||||
}
|
||||
|
||||
// remove any relationships that reference the deleted packages
|
||||
var relationships []artifact.Relationship
|
||||
for _, rel := range b.sbom.Relationships {
|
||||
if _, ok := deleted[rel.From.ID()]; ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := deleted[rel.To.ID()]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// only keep relationships that don't reference the deleted packages
|
||||
relationships = append(relationships, rel)
|
||||
}
|
||||
|
||||
b.sbom.Relationships = relationships
|
||||
b.onWriteEvent()
|
||||
}
|
||||
|
||||
func (b sbomBuilder) AddRelationships(relationship ...artifact.Relationship) {
|
||||
@@ -113,7 +73,6 @@ func (b sbomBuilder) AddRelationships(relationship ...artifact.Relationship) {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sbom.Relationships = append(b.sbom.Relationships, relationship...)
|
||||
b.onWriteEvent()
|
||||
}
|
||||
|
||||
func (b sbomBuilder) SetLinuxDistribution(release linux.Release) {
|
||||
@@ -121,5 +80,4 @@ func (b sbomBuilder) SetLinuxDistribution(release linux.Release) {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sbom.Artifacts.LinuxDistribution = &release
|
||||
b.onWriteEvent()
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
package sbomsync
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/magiconair/properties/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
func TestNewBuilder(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
sbom sbom.SBOM
|
||||
}{
|
||||
{
|
||||
"TestNewBuilder with empty sbom",
|
||||
sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
Packages: pkg.NewCollection(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
builder := NewBuilder(&tt.sbom)
|
||||
builder.AddPackages(pkg.Package{})
|
||||
accessor := builder.(Accessor)
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
packageCount := s.Artifacts.Packages.PackageCount()
|
||||
assert.Equal(t, packageCount, 1, "expected 1 package in sbom")
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_sbomBuilder_DeletePackages(t *testing.T) {
|
||||
testPackage := pkg.Package{
|
||||
Name: "test",
|
||||
Version: "1.0.0",
|
||||
Type: pkg.DebPkg,
|
||||
}
|
||||
testPackage.SetID()
|
||||
|
||||
keepMe := pkg.Package{
|
||||
Name: "keepMe",
|
||||
Version: "1.0.0",
|
||||
Type: pkg.DebPkg,
|
||||
}
|
||||
|
||||
prexistingRelationships := []artifact.Relationship{
|
||||
{
|
||||
From: testPackage,
|
||||
To: testPackage,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
sbom sbom.SBOM
|
||||
}{
|
||||
{
|
||||
"Test_sbomBuilder_DeletePackages deletes a given package",
|
||||
sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
Packages: pkg.NewCollection(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
builder := NewBuilder(&tt.sbom)
|
||||
builder.AddPackages(testPackage, keepMe)
|
||||
accessor := builder.(Accessor)
|
||||
accessor.WriteToSBOM(func(s *sbom.SBOM) {
|
||||
s.Relationships = prexistingRelationships
|
||||
})
|
||||
|
||||
builder.DeletePackages(testPackage.ID())
|
||||
newAccess := builder.(Accessor)
|
||||
newAccess.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
packageCount := s.Artifacts.Packages.PackageCount()
|
||||
|
||||
// deleted target package
|
||||
assert.Equal(t, packageCount, 1, "expected 1 packages in sbom")
|
||||
relationshipCount := len(s.Relationships)
|
||||
|
||||
// deleted relationships that reference the deleted package
|
||||
assert.Equal(t, relationshipCount, 0, "expected 0 relationships in sbom")
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at 2024-05-23 08:47:23.204981 -0400 EDT m=+0.050881068
|
||||
// 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.24.0"
|
||||
const Version = "3.23"
|
||||
|
||||
var licenseIDs = map[string]string{
|
||||
"0bsd": "0BSD",
|
||||
"3.0.0dslicer1.0": "3D-Slicer-1.0",
|
||||
"3.0dslicer1.0": "3D-Slicer-1.0",
|
||||
"3dslicer1.0": "3D-Slicer-1.0",
|
||||
"aal": "AAL",
|
||||
"abstyles": "Abstyles",
|
||||
"adacoredoc": "AdaCore-doc",
|
||||
@@ -59,14 +56,12 @@ var licenseIDs = map[string]string{
|
||||
"agpl3only": "AGPL-3.0-only",
|
||||
"agpl3orlater": "AGPL-3.0-or-later",
|
||||
"aladdin": "Aladdin",
|
||||
"amdnewlib": "AMD-newlib",
|
||||
"amdplpa": "AMDPLPA",
|
||||
"aml": "AML",
|
||||
"amlglslang": "AML-glslang",
|
||||
"ampas": "AMPAS",
|
||||
"antlrpd": "ANTLR-PD",
|
||||
"antlrpdfallback": "ANTLR-PD-fallback",
|
||||
"anyosi": "any-OSI",
|
||||
"apache1": "Apache-1.0",
|
||||
"apache1.0": "Apache-1.0",
|
||||
"apache1.0.0": "Apache-1.0",
|
||||
@@ -141,21 +136,18 @@ var licenseIDs = map[string]string{
|
||||
"bsd1clause": "BSD-1-Clause",
|
||||
"bsd2.0.0clause": "BSD-2-Clause",
|
||||
"bsd2.0.0clausedarwin": "BSD-2-Clause-Darwin",
|
||||
"bsd2.0.0clausefirstlines": "BSD-2-Clause-first-lines",
|
||||
"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.0clausefirstlines": "BSD-2-Clause-first-lines",
|
||||
"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",
|
||||
"bsd2clausefirstlines": "BSD-2-Clause-first-lines",
|
||||
"bsd2clausefreebsd": "BSD-2-Clause-Views",
|
||||
"bsd2clausenetbsd": "BSD-2-Clause",
|
||||
"bsd2clausepatent": "BSD-2-Clause-Patent",
|
||||
@@ -245,7 +237,6 @@ var licenseIDs = map[string]string{
|
||||
"cal1combinedworkexception": "CAL-1.0-Combined-Work-Exception",
|
||||
"caldera": "Caldera",
|
||||
"calderanopreamble": "Caldera-no-preamble",
|
||||
"catharon": "Catharon",
|
||||
"catosl1": "CATOSL-1.1",
|
||||
"catosl1.1": "CATOSL-1.1",
|
||||
"catosl1.1.0": "CATOSL-1.1",
|
||||
@@ -486,7 +477,6 @@ var licenseIDs = map[string]string{
|
||||
"cuda1.0": "C-UDA-1.0",
|
||||
"cuda1.0.0": "C-UDA-1.0",
|
||||
"curl": "curl",
|
||||
"cvetou": "cve-tou",
|
||||
"dec3.0.0clause": "DEC-3-Clause",
|
||||
"dec3.0clause": "DEC-3-Clause",
|
||||
"dec3clause": "DEC-3-Clause",
|
||||
@@ -711,7 +701,6 @@ var licenseIDs = map[string]string{
|
||||
"gsoap1.3b": "gSOAP-1.3b",
|
||||
"gsoap1b": "gSOAP-1.3b",
|
||||
"gtkbook": "gtkbook",
|
||||
"gutmann": "Gutmann",
|
||||
"haskellreport": "HaskellReport",
|
||||
"hdparm": "hdparm",
|
||||
"hippocratic2": "Hippocratic-2.1",
|
||||
@@ -727,27 +716,19 @@ var licenseIDs = map[string]string{
|
||||
"hpnddec": "HPND-DEC",
|
||||
"hpnddoc": "HPND-doc",
|
||||
"hpnddocsell": "HPND-doc-sell",
|
||||
"hpndexport2.0.0us": "HPND-export2-US",
|
||||
"hpndexport2.0us": "HPND-export2-US",
|
||||
"hpndexport2us": "HPND-export2-US",
|
||||
"hpndexportus": "HPND-export-US",
|
||||
"hpndexportusacknowledgement": "HPND-export-US-acknowledgement",
|
||||
"hpndexportusmodify": "HPND-export-US-modify",
|
||||
"hpndfenneberglivingston": "HPND-Fenneberg-Livingston",
|
||||
"hpndinriaimag": "HPND-INRIA-IMAG",
|
||||
"hpndintel": "HPND-Intel",
|
||||
"hpndkevlinhenney": "HPND-Kevlin-Henney",
|
||||
"hpndmarkuskuhn": "HPND-Markus-Kuhn",
|
||||
"hpndmerchantabilityvariant": "HPND-merchantability-variant",
|
||||
"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",
|
||||
"hpndsellvariantmitdisclaimerrev": "HPND-sell-variant-MIT-disclaimer-rev",
|
||||
"hpnduc": "HPND-UC",
|
||||
"hpnducexportus": "HPND-UC-export-US",
|
||||
"htmltidy": "HTMLTIDY",
|
||||
"ibmpibs": "IBM-pibs",
|
||||
"icu": "ICU",
|
||||
@@ -905,7 +886,6 @@ var licenseIDs = map[string]string{
|
||||
"mitenna": "MIT-enna",
|
||||
"mitfeh": "MIT-feh",
|
||||
"mitfestival": "MIT-Festival",
|
||||
"mitkhronosold": "MIT-Khronos-old",
|
||||
"mitmodernvariant": "MIT-Modern-Variant",
|
||||
"mitnfa": "MITNFA",
|
||||
"mitopengroup": "MIT-open-group",
|
||||
@@ -952,11 +932,9 @@ var licenseIDs = map[string]string{
|
||||
"nbpl1": "NBPL-1.0",
|
||||
"nbpl1.0": "NBPL-1.0",
|
||||
"nbpl1.0.0": "NBPL-1.0",
|
||||
"ncbipd": "NCBI-PD",
|
||||
"ncgluk2": "NCGL-UK-2.0",
|
||||
"ncgluk2.0": "NCGL-UK-2.0",
|
||||
"ncgluk2.0.0": "NCGL-UK-2.0",
|
||||
"ncl": "NCL",
|
||||
"ncsa": "NCSA",
|
||||
"netcdf": "NetCDF",
|
||||
"netsnmp": "Net-SNMP",
|
||||
@@ -990,7 +968,6 @@ var licenseIDs = map[string]string{
|
||||
"ntp": "NTP",
|
||||
"ntp0": "NTP-0",
|
||||
"nunit": "Nunit",
|
||||
"oar": "OAR",
|
||||
"occtpl": "OCCT-PL",
|
||||
"oclc2": "OCLC-2.0",
|
||||
"oclc2.0": "OCLC-2.0",
|
||||
@@ -1121,7 +1098,6 @@ var licenseIDs = map[string]string{
|
||||
"php3.01": "PHP-3.01",
|
||||
"php3.01.0": "PHP-3.01",
|
||||
"pixar": "Pixar",
|
||||
"pkgconf": "pkgconf",
|
||||
"plexus": "Plexus",
|
||||
"pnmstitch": "pnmstitch",
|
||||
"polyformnoncommercial1": "PolyForm-Noncommercial-1.0.0",
|
||||
@@ -1131,7 +1107,6 @@ var licenseIDs = map[string]string{
|
||||
"polyformsmallbusiness1.0": "PolyForm-Small-Business-1.0.0",
|
||||
"polyformsmallbusiness1.0.0": "PolyForm-Small-Business-1.0.0",
|
||||
"postgresql": "PostgreSQL",
|
||||
"ppl": "PPL",
|
||||
"psf2": "PSF-2.0",
|
||||
"psf2.0": "PSF-2.0",
|
||||
"psf2.0.0": "PSF-2.0",
|
||||
@@ -1231,9 +1206,6 @@ var licenseIDs = map[string]string{
|
||||
"sugarcrm1.1": "SugarCRM-1.1.3",
|
||||
"sugarcrm1.1.3": "SugarCRM-1.1.3",
|
||||
"sunppp": "Sun-PPP",
|
||||
"sunppp2000": "Sun-PPP-2000",
|
||||
"sunppp2000.0": "Sun-PPP-2000",
|
||||
"sunppp2000.0.0": "Sun-PPP-2000",
|
||||
"sunpro": "SunPro",
|
||||
"swl": "SWL",
|
||||
"swrule": "swrule",
|
||||
@@ -1247,7 +1219,6 @@ var licenseIDs = map[string]string{
|
||||
"tgppl1": "TGPPL-1.0",
|
||||
"tgppl1.0": "TGPPL-1.0",
|
||||
"tgppl1.0.0": "TGPPL-1.0",
|
||||
"threeparttable": "threeparttable",
|
||||
"tmate": "TMate",
|
||||
"torque1": "TORQUE-1.1",
|
||||
"torque1.1": "TORQUE-1.1",
|
||||
@@ -1331,7 +1302,6 @@ var licenseIDs = map[string]string{
|
||||
"xnet": "Xnet",
|
||||
"xpp": "xpp",
|
||||
"xskat": "XSkat",
|
||||
"xzoom": "xzoom",
|
||||
"ypl1": "YPL-1.0",
|
||||
"ypl1.0": "YPL-1.0",
|
||||
"ypl1.0.0": "YPL-1.0",
|
||||
|
||||
@@ -33,9 +33,5 @@ func SplitAny(s string, seps string) []string {
|
||||
splitter := func(r rune) bool {
|
||||
return strings.ContainsRune(seps, r)
|
||||
}
|
||||
result := strings.FieldsFunc(s, splitter)
|
||||
if len(result) == 0 {
|
||||
return []string{s}
|
||||
}
|
||||
return result
|
||||
return strings.FieldsFunc(s, splitter)
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ func TestSplitAny(t *testing.T) {
|
||||
name: "empty",
|
||||
input: "",
|
||||
fields: ",",
|
||||
want: []string{""},
|
||||
want: []string{},
|
||||
},
|
||||
{
|
||||
name: "multiple separators",
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/lua"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/nix"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/php"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/python"
|
||||
@@ -111,7 +110,6 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
|
||||
),
|
||||
newSimplePackageTaskFactory(java.NewNativeImageCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "java"),
|
||||
newSimplePackageTaskFactory(nix.NewStoreCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "nix"),
|
||||
newSimplePackageTaskFactory(lua.NewPackageCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "lua"),
|
||||
|
||||
// other package catalogers ///////////////////////////////////////////////////////////////////////////
|
||||
newPackageTaskFactory(
|
||||
|
||||
@@ -4,12 +4,10 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/internal/relationship"
|
||||
"github.com/anchore/syft/internal/relationship/binary"
|
||||
"github.com/anchore/syft/internal/sbomsync"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/cataloging"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
@@ -24,9 +22,8 @@ func (s sourceIdentifierAdapter) ID() artifact.ID {
|
||||
}
|
||||
|
||||
func NewRelationshipsTask(cfg cataloging.RelationshipsConfig, src source.Description) Task {
|
||||
fn := func(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
|
||||
finalizeRelationships(
|
||||
resolver,
|
||||
fn := func(_ context.Context, _ file.Resolver, builder sbomsync.Builder) error {
|
||||
relationship.Finalize(
|
||||
builder,
|
||||
cfg,
|
||||
&sourceIdentifierAdapter{desc: src})
|
||||
@@ -36,43 +33,3 @@ func NewRelationshipsTask(cfg cataloging.RelationshipsConfig, src source.Descrip
|
||||
|
||||
return NewTask("relationships-cataloger", fn)
|
||||
}
|
||||
|
||||
func finalizeRelationships(resolver file.Resolver, builder sbomsync.Builder, cfg cataloging.RelationshipsConfig, src artifact.Identifiable) {
|
||||
accessor := builder.(sbomsync.Accessor)
|
||||
|
||||
// remove ELF packages and Binary packages that are already
|
||||
// represented by a source package (e.g. a package that is evident by some package manager)
|
||||
builder.DeletePackages(binary.PackagesToRemove(resolver, accessor)...)
|
||||
|
||||
// add relationships showing packages that are evident by a file which is owned by another package (package-to-package)
|
||||
if cfg.PackageFileOwnershipOverlap {
|
||||
relationship.ByFileOwnershipOverlapWorker(accessor)
|
||||
}
|
||||
|
||||
// conditionally remove binary packages based on file ownership overlap relationships found
|
||||
// https://github.com/anchore/syft/issues/931
|
||||
if cfg.ExcludeBinaryPackagesWithFileOwnershipOverlap {
|
||||
relationship.ExcludeBinariesByFileOwnershipOverlap(accessor)
|
||||
}
|
||||
|
||||
// add the new relationships for executables to the SBOM
|
||||
newBinaryRelationships := binary.NewDependencyRelationships(resolver, accessor)
|
||||
accessor.WriteToSBOM(func(s *sbom.SBOM) {
|
||||
s.Relationships = append(s.Relationships, newBinaryRelationships...)
|
||||
})
|
||||
builder.AddRelationships(newBinaryRelationships...)
|
||||
// add source "contains package" relationship (source-to-package)
|
||||
var sourceRelationships []artifact.Relationship
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
sourceRelationships = relationship.ToSource(src, s.Artifacts.Packages)
|
||||
})
|
||||
builder.AddRelationships(sourceRelationships...)
|
||||
|
||||
// add evident-by relationships (package-to-file)
|
||||
var evidentByRelationships []artifact.Relationship
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
evidentByRelationships = relationship.EvidentBy(s.Artifacts.Packages)
|
||||
})
|
||||
|
||||
builder.AddRelationships(evidentByRelationships...)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ Given a version number format `MODEL.REVISION.ADDITION`:
|
||||
|
||||
## Adding a New `pkg.*Metadata` Type
|
||||
|
||||
When adding a new `pkg.*Metadata` that is assigned to the `pkg.Package.Metadata` struct field you must add a test case to `cmd/syft/internal/test/integration/catalog_packages_cases_test.go` that exercises the new package type with the new metadata.
|
||||
When adding a new `pkg.*Metadata` that is assigned to the `pkg.Package.Metadata` struct field you must add a test case to `test/integration/catalog_packages_cases_test.go` that exercises the new package type with the new metadata.
|
||||
|
||||
Additionally it is important to generate a new JSON schema since the `pkg.Package.Metadata` field is covered by the schema.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "anchore.io/schema/syft/json/16.0.12/document",
|
||||
"$id": "anchore.io/schema/syft/json/16.0.7/document",
|
||||
"$ref": "#/$defs/Document",
|
||||
"$defs": {
|
||||
"AlpmDbEntry": {
|
||||
@@ -46,18 +46,6 @@
|
||||
"$ref": "#/$defs/AlpmFileRecord"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"provides": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"depends": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
@@ -870,12 +858,6 @@
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"goExperiments": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
@@ -1348,46 +1330,6 @@
|
||||
"accessPath"
|
||||
]
|
||||
},
|
||||
"LuarocksPackage": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
"license": {
|
||||
"type": "string"
|
||||
},
|
||||
"homepage": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"dependencies": {
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"version",
|
||||
"license",
|
||||
"homepage",
|
||||
"description",
|
||||
"url",
|
||||
"dependencies"
|
||||
]
|
||||
},
|
||||
"MicrosoftKbPatch": {
|
||||
"properties": {
|
||||
"product_id": {
|
||||
@@ -1542,9 +1484,6 @@
|
||||
{
|
||||
"$ref": "#/$defs/LinuxKernelModule"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/LuarocksPackage"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/MicrosoftKbPatch"
|
||||
},
|
||||
@@ -1979,21 +1918,6 @@
|
||||
},
|
||||
"directUrlOrigin": {
|
||||
"$ref": "#/$defs/PythonDirectURLOriginInfo"
|
||||
},
|
||||
"requiresPython": {
|
||||
"type": "string"
|
||||
},
|
||||
"requiresDist": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"providesExtra": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
@@ -2168,18 +2092,6 @@
|
||||
"modularityLabel": {
|
||||
"type": "string"
|
||||
},
|
||||
"provides": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"requires": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"files": {
|
||||
"items": {
|
||||
"$ref": "#/$defs/RpmFileRecord"
|
||||
@@ -2236,18 +2148,6 @@
|
||||
"modularityLabel": {
|
||||
"type": "string"
|
||||
},
|
||||
"provides": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"requires": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"files": {
|
||||
"items": {
|
||||
"$ref": "#/$defs/RpmFileRecord"
|
||||
|
||||
+24
-11
@@ -4,9 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/sbomsync"
|
||||
@@ -61,9 +63,9 @@ func CreateSBOM(ctx context.Context, src source.Source, cfg *CreateSBOMConfig) (
|
||||
}
|
||||
|
||||
catalogingProgress := monitorCatalogingTask(src.ID(), taskGroups)
|
||||
packageCatalogingProgress := monitorPackageCatalogingTask()
|
||||
packageCatalogingProgress := monitorPackageCatalogingTask(s.Artifacts.Packages)
|
||||
|
||||
builder := sbomsync.NewBuilder(&s, monitorPackageCount(packageCatalogingProgress))
|
||||
builder := sbomsync.NewBuilder(&s)
|
||||
for i := range taskGroups {
|
||||
err := task.NewTaskExecutor(taskGroups[i], cfg.Parallelism).Execute(ctx, resolver, builder, catalogingProgress)
|
||||
if err != nil {
|
||||
@@ -78,14 +80,7 @@ func CreateSBOM(ctx context.Context, src source.Source, cfg *CreateSBOMConfig) (
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func monitorPackageCount(prog *monitor.CatalogerTaskProgress) func(s *sbom.SBOM) {
|
||||
return func(s *sbom.SBOM) {
|
||||
count := humanize.Comma(int64(s.Artifacts.Packages.PackageCount()))
|
||||
prog.AtomicStage.Set(fmt.Sprintf("%s packages", count))
|
||||
}
|
||||
}
|
||||
|
||||
func monitorPackageCatalogingTask() *monitor.CatalogerTaskProgress {
|
||||
func monitorPackageCatalogingTask(pkgs *pkg.Collection) *monitor.CatalogerTaskProgress {
|
||||
info := monitor.GenericTask{
|
||||
Title: monitor.Title{
|
||||
Default: "Packages",
|
||||
@@ -95,7 +90,25 @@ func monitorPackageCatalogingTask() *monitor.CatalogerTaskProgress {
|
||||
ParentID: monitor.TopLevelCatalogingTaskID,
|
||||
}
|
||||
|
||||
return bus.StartCatalogerTask(info, -1, "")
|
||||
prog := bus.StartCatalogerTask(info, -1, "")
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(200 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
<-ticker.C
|
||||
|
||||
count := humanize.Comma(int64(pkgs.PackageCount()))
|
||||
prog.AtomicStage.Set(fmt.Sprintf("%s packages", count))
|
||||
|
||||
if progress.IsCompleted(prog) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return prog
|
||||
}
|
||||
|
||||
func monitorCatalogingTask(srcID artifact.ID, tasks [][]task.Task) *monitor.CatalogerTaskProgress {
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/bmatcuk/doublestar/v4"
|
||||
"github.com/dustin/go-humanize"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/mimetype"
|
||||
@@ -61,8 +60,24 @@ func (i *Cataloger) Catalog(resolver file.Resolver) (map[file.Coordinates]file.E
|
||||
for _, loc := range locs {
|
||||
prog.AtomicStage.Set(loc.Path())
|
||||
|
||||
exec := processExecutableLocation(loc, resolver)
|
||||
reader, err := resolver.FileContentsByLocation(loc)
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Warnf("unable to get file contents for %q", loc.RealPath)
|
||||
continue
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if exec != nil {
|
||||
prog.Increment()
|
||||
results[loc.Coordinates] = *exec
|
||||
@@ -77,29 +92,6 @@ func (i *Cataloger) Catalog(resolver file.Resolver) (map[file.Coordinates]file.E
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func processExecutableLocation(loc file.Location, resolver file.Resolver) *file.Executable {
|
||||
reader, err := resolver.FileContentsByLocation(loc)
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Warnf("unable to get file contents for %q", loc.RealPath)
|
||||
return nil
|
||||
}
|
||||
defer internal.CloseAndLogError(reader, loc.RealPath)
|
||||
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
|
||||
exec, err := processExecutable(loc, uReader)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Warnf("unable to process executable %q", loc.RealPath)
|
||||
}
|
||||
return exec
|
||||
}
|
||||
|
||||
func catalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
|
||||
info := monitor.GenericTask{
|
||||
Title: monitor.Title{
|
||||
|
||||
@@ -13,13 +13,6 @@ type Coordinates struct {
|
||||
FileSystemID string `json:"layerID,omitempty" cyclonedx:"layerID"` // An ID representing the filesystem. For container images, this is a layer digest. For directories or a root filesystem, this is blank.
|
||||
}
|
||||
|
||||
func NewCoordinates(realPath, fsID string) Coordinates {
|
||||
return Coordinates{
|
||||
RealPath: realPath,
|
||||
FileSystemID: fsID,
|
||||
}
|
||||
}
|
||||
|
||||
func (c Coordinates) ID() artifact.ID {
|
||||
f, err := artifact.IDByHash(c)
|
||||
if err != nil {
|
||||
|
||||
@@ -124,7 +124,7 @@ func ToFormatModel(s sbom.SBOM) *spdx.Document {
|
||||
CreationInfo: &spdx.CreationInfo{
|
||||
// 6.7: License List Version
|
||||
// Cardinality: optional, one
|
||||
LicenseListVersion: trimPatchVersion(spdxlicense.Version),
|
||||
LicenseListVersion: spdxlicense.Version,
|
||||
|
||||
// 6.8: Creators: may have multiple keys for Person, Organization
|
||||
// and/or Tool
|
||||
@@ -791,13 +791,3 @@ func newPackageVerificationCode(p pkg.Package, sbom sbom.SBOM) *spdx.PackageVeri
|
||||
Value: fmt.Sprintf("%+x", hasher.Sum(nil)),
|
||||
}
|
||||
}
|
||||
|
||||
// SPDX 2.2 spec requires that the patch version be removed from the semver string
|
||||
// for the license list version field
|
||||
func trimPatchVersion(semver string) string {
|
||||
parts := strings.Split(semver, ".")
|
||||
if len(parts) >= 3 {
|
||||
return strings.Join(parts[:2], ".")
|
||||
}
|
||||
return semver
|
||||
}
|
||||
|
||||
@@ -381,13 +381,6 @@ func collectDocRelationships(spdxIDMap map[string]any, doc *spdx.Document) (out
|
||||
}
|
||||
} else {
|
||||
switch helpers.RelationshipType(r.Relationship) {
|
||||
case helpers.DependencyOfRelationship:
|
||||
typ = artifact.DependencyOfRelationship
|
||||
to = toPackage
|
||||
case helpers.DependsOnRelationship:
|
||||
typ = artifact.DependencyOfRelationship
|
||||
to = from
|
||||
from = toPackage
|
||||
case helpers.ContainsRelationship:
|
||||
typ = artifact.ContainsRelationship
|
||||
to = toPackage
|
||||
|
||||
@@ -414,66 +414,6 @@ func Test_toSyftRelationships(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dependency-of relationship",
|
||||
args: args{
|
||||
spdxIDMap: map[string]any{
|
||||
string(toSPDXID(pkg2)): pkg2,
|
||||
string(toSPDXID(pkg3)): pkg3,
|
||||
},
|
||||
doc: &spdx.Document{
|
||||
Relationships: []*spdx.Relationship{
|
||||
{
|
||||
RefA: common.DocElementID{
|
||||
ElementRefID: toSPDXID(pkg2),
|
||||
},
|
||||
RefB: common.DocElementID{
|
||||
ElementRefID: toSPDXID(pkg3),
|
||||
},
|
||||
Relationship: spdx.RelationshipDependencyOf,
|
||||
RelationshipComment: "dependency-of: indicates that the package in RefA is a dependency of the package in RefB",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []artifact.Relationship{
|
||||
{
|
||||
From: pkg2,
|
||||
To: pkg3,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dependends-on relationship",
|
||||
args: args{
|
||||
spdxIDMap: map[string]any{
|
||||
string(toSPDXID(pkg2)): pkg2,
|
||||
string(toSPDXID(pkg3)): pkg3,
|
||||
},
|
||||
doc: &spdx.Document{
|
||||
Relationships: []*spdx.Relationship{
|
||||
{
|
||||
RefA: common.DocElementID{
|
||||
ElementRefID: toSPDXID(pkg3),
|
||||
},
|
||||
RefB: common.DocElementID{
|
||||
ElementRefID: toSPDXID(pkg2),
|
||||
},
|
||||
Relationship: spdx.RelationshipDependsOn,
|
||||
RelationshipComment: "dependends-on: indicates that the package in RefA depends on the package in RefB",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []artifact.Relationship{
|
||||
{
|
||||
From: pkg2,
|
||||
To: pkg3,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/format/internal/stream"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
@@ -22,16 +20,10 @@ func NewDecoderCollection(decoders ...sbom.FormatDecoder) sbom.FormatDecoder {
|
||||
}
|
||||
|
||||
// Decode takes a set of bytes and attempts to decode it into an SBOM relative to the decoders in the collection.
|
||||
func (c *DecoderCollection) Decode(r io.Reader) (*sbom.SBOM, sbom.FormatID, string, error) {
|
||||
if r == nil {
|
||||
func (c *DecoderCollection) Decode(reader io.Reader) (*sbom.SBOM, sbom.FormatID, string, error) {
|
||||
if reader == nil {
|
||||
return nil, "", "", fmt.Errorf("no SBOM bytes provided")
|
||||
}
|
||||
|
||||
reader, err := stream.SeekableReader(r)
|
||||
if err != nil {
|
||||
return nil, "", "", fmt.Errorf("unable to create a seekable reader: %w", err)
|
||||
}
|
||||
|
||||
var bestID sbom.FormatID
|
||||
for _, d := range c.decoders {
|
||||
id, version := d.Identify(reader)
|
||||
@@ -53,17 +45,10 @@ func (c *DecoderCollection) Decode(r io.Reader) (*sbom.SBOM, sbom.FormatID, stri
|
||||
}
|
||||
|
||||
// Identify takes a set of bytes and attempts to identify the format of the SBOM relative to the decoders in the collection.
|
||||
func (c *DecoderCollection) Identify(r io.Reader) (sbom.FormatID, string) {
|
||||
if r == nil {
|
||||
func (c *DecoderCollection) Identify(reader io.Reader) (sbom.FormatID, string) {
|
||||
if reader == nil {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
reader, err := stream.SeekableReader(r)
|
||||
if err != nil {
|
||||
log.Debugf("unable to create a seekable reader: %v", err)
|
||||
return "", ""
|
||||
}
|
||||
|
||||
for _, d := range c.decoders {
|
||||
id, version := d.Identify(reader)
|
||||
if id != "" && version != "" {
|
||||
|
||||
@@ -2,14 +2,12 @@ package format
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/format/spdxjson"
|
||||
"github.com/anchore/syft/syft/format/syftjson"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
@@ -39,17 +37,6 @@ func TestIdentify(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeUnseekable(t *testing.T) {
|
||||
reader, err := os.Open("spdxjson/test-fixtures/spdx/example7-go-module.spdx.json")
|
||||
assert.NoError(t, err)
|
||||
|
||||
// io.NopCloser wraps the reader in a non-seekable type
|
||||
unseekableReader := io.NopCloser(reader)
|
||||
_, formatID, _, err := Decode(unseekableReader)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, spdxjson.ID, formatID)
|
||||
}
|
||||
|
||||
func TestFormats_EmptyInput(t *testing.T) {
|
||||
for _, format := range Decoders() {
|
||||
name := strings.Split(fmt.Sprintf("%#v", format), "{")[0]
|
||||
|
||||
@@ -8,7 +8,7 @@ const (
|
||||
OtherReferenceCategory ReferenceCategory = "OTHER"
|
||||
)
|
||||
|
||||
// source: https://spdx.github.io/spdx-spec/v2.2.2/external-repository-identifiers/
|
||||
// source: https://spdx.github.io/spdx-spec/appendix-VI-external-repository-identifiers/
|
||||
|
||||
type ExternalRefType string
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
)
|
||||
|
||||
func License(p pkg.Package) (concluded, declared string) {
|
||||
// source: https://spdx.github.io/spdx-spec/v2.3/package-information/#713-concluded-license-field
|
||||
// source: https://spdx.github.io/spdx-spec/3-package-information/#313-concluded-license
|
||||
// The options to populate this field are limited to:
|
||||
// A valid SPDX License Expression as defined in Annex D;
|
||||
// A valid SPDX License Expression as defined in Appendix IV;
|
||||
// NONE, if the SPDX file creator concludes there is no license available for this package; or
|
||||
// NOASSERTION if:
|
||||
// (i) the SPDX file creator has attempted to but cannot reach a reasonable objective determination;
|
||||
|
||||
@@ -27,7 +27,6 @@ func Test_OriginatorSupplier(t *testing.T) {
|
||||
pkg.HackageStackYamlLockEntry{},
|
||||
pkg.HackageStackYamlEntry{},
|
||||
pkg.LinuxKernel{},
|
||||
pkg.LuaRocksPackage{},
|
||||
pkg.MicrosoftKbPatch{},
|
||||
pkg.NixStoreEntry{},
|
||||
pkg.NpmPackageLockEntry{},
|
||||
@@ -186,14 +185,6 @@ func Test_OriginatorSupplier(t *testing.T) {
|
||||
originator: "Person: auth",
|
||||
supplier: "Person: auth",
|
||||
},
|
||||
{
|
||||
name: "from Lua Rockspecs",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.LuaRocksPackage{},
|
||||
},
|
||||
originator: "",
|
||||
supplier: "",
|
||||
},
|
||||
{
|
||||
name: "from npm",
|
||||
input: pkg.Package{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package helpers
|
||||
|
||||
// source: https://spdx.github.io/spdx-spec/v2.2.2/relationships-between-SPDX-elements/
|
||||
// source: https://spdx.github.io/spdx-spec/7-relationships-between-SPDX-elements/
|
||||
type RelationshipType string
|
||||
|
||||
const (
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
//nolint:funlen, gocyclo
|
||||
//nolint:funlen
|
||||
func SourceInfo(p pkg.Package) string {
|
||||
answer := ""
|
||||
switch p.Type {
|
||||
@@ -58,8 +58,6 @@ func SourceInfo(p pkg.Package) string {
|
||||
answer = "acquired package info from nix store path"
|
||||
case pkg.Rpkg:
|
||||
answer = "acquired package info from R-package DESCRIPTION file"
|
||||
case pkg.LuaRocksPkg:
|
||||
answer = "acquired package info from Rockspec package file"
|
||||
case pkg.SwiftPkg:
|
||||
answer = "acquired package info from resolved Swift package manifest"
|
||||
case pkg.GithubActionPkg, pkg.GithubActionWorkflowPkg:
|
||||
|
||||
@@ -247,14 +247,6 @@ func Test_SourceInfo(t *testing.T) {
|
||||
"acquired package info from R-package DESCRIPTION file",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.LuaRocksPkg,
|
||||
},
|
||||
expected: []string{
|
||||
"acquired package info from Rockspec package file",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.SwiftPkg,
|
||||
|
||||
@@ -3,14 +3,14 @@ package spdxjson
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/format/internal/spdxutil"
|
||||
"github.com/anchore/syft/syft/format/internal/testutil"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "package-1",
|
||||
"SPDXID": "SPDXRef-Package-python-package-1-5a2b1ae000fcb51e",
|
||||
"SPDXID": "SPDXRef-Package-python-package-1-fb6bef15e281ea43",
|
||||
"versionInfo": "1.0.1",
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
@@ -75,7 +75,7 @@
|
||||
"relationships": [
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DocumentRoot-Directory-some-path",
|
||||
"relatedSpdxElement": "SPDXRef-Package-python-package-1-5a2b1ae000fcb51e",
|
||||
"relatedSpdxElement": "SPDXRef-Package-python-package-1-fb6bef15e281ea43",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "package-1",
|
||||
"SPDXID": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"SPDXID": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"versionInfo": "1.0.1",
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
@@ -89,7 +89,7 @@
|
||||
"relationships": [
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DocumentRoot-Image-user-image-input",
|
||||
"relatedSpdxElement": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"relatedSpdxElement": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "package-1",
|
||||
"SPDXID": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"SPDXID": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"versionInfo": "1.0.1",
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
@@ -198,38 +198,38 @@
|
||||
],
|
||||
"relationships": [
|
||||
{
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"relatedSpdxElement": "SPDXRef-File-f1-5265a4dde3edbf7c",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"relatedSpdxElement": "SPDXRef-File-z1-f5-839d99ee67d9d174",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"relatedSpdxElement": "SPDXRef-File-a1-f6-9c2f7510199b17f6",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"relatedSpdxElement": "SPDXRef-File-d2-f4-c641caa71518099f",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"relatedSpdxElement": "SPDXRef-File-d1-f3-c6f5b29dca12661f",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"spdxElementId": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"relatedSpdxElement": "SPDXRef-File-f2-f9e49132a4b96ccd",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DocumentRoot-Image-user-image-input",
|
||||
"relatedSpdxElement": "SPDXRef-Package-python-package-1-c5cf7ac34cbca450",
|
||||
"relatedSpdxElement": "SPDXRef-Package-python-package-1-80210ebcba92e632",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -84,7 +84,7 @@ ExternalRef: PACKAGE-MANAGER purl pkg:deb/debian/package-2@2.0.1
|
||||
##### Package: package-1
|
||||
|
||||
PackageName: package-1
|
||||
SPDXID: SPDXRef-Package-python-package-1-c5cf7ac34cbca450
|
||||
SPDXID: SPDXRef-Package-python-package-1-80210ebcba92e632
|
||||
PackageVersion: 1.0.1
|
||||
PackageSupplier: NOASSERTION
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
@@ -98,13 +98,13 @@ ExternalRef: PACKAGE-MANAGER purl a-purl-1
|
||||
|
||||
##### Relationships
|
||||
|
||||
Relationship: SPDXRef-Package-python-package-1-c5cf7ac34cbca450 CONTAINS SPDXRef-File-f1-5265a4dde3edbf7c
|
||||
Relationship: SPDXRef-Package-python-package-1-c5cf7ac34cbca450 CONTAINS SPDXRef-File-z1-f5-839d99ee67d9d174
|
||||
Relationship: SPDXRef-Package-python-package-1-c5cf7ac34cbca450 CONTAINS SPDXRef-File-a1-f6-9c2f7510199b17f6
|
||||
Relationship: SPDXRef-Package-python-package-1-c5cf7ac34cbca450 CONTAINS SPDXRef-File-d2-f4-c641caa71518099f
|
||||
Relationship: SPDXRef-Package-python-package-1-c5cf7ac34cbca450 CONTAINS SPDXRef-File-d1-f3-c6f5b29dca12661f
|
||||
Relationship: SPDXRef-Package-python-package-1-c5cf7ac34cbca450 CONTAINS SPDXRef-File-f2-f9e49132a4b96ccd
|
||||
Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-python-package-1-c5cf7ac34cbca450
|
||||
Relationship: SPDXRef-Package-python-package-1-80210ebcba92e632 CONTAINS SPDXRef-File-f1-5265a4dde3edbf7c
|
||||
Relationship: SPDXRef-Package-python-package-1-80210ebcba92e632 CONTAINS SPDXRef-File-z1-f5-839d99ee67d9d174
|
||||
Relationship: SPDXRef-Package-python-package-1-80210ebcba92e632 CONTAINS SPDXRef-File-a1-f6-9c2f7510199b17f6
|
||||
Relationship: SPDXRef-Package-python-package-1-80210ebcba92e632 CONTAINS SPDXRef-File-d2-f4-c641caa71518099f
|
||||
Relationship: SPDXRef-Package-python-package-1-80210ebcba92e632 CONTAINS SPDXRef-File-d1-f3-c6f5b29dca12661f
|
||||
Relationship: SPDXRef-Package-python-package-1-80210ebcba92e632 CONTAINS SPDXRef-File-f2-f9e49132a4b96ccd
|
||||
Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-python-package-1-80210ebcba92e632
|
||||
Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-deb-package-2-4b756c6f6fb127a3
|
||||
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DocumentRoot-Image-user-image-input
|
||||
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ ExternalRef: PACKAGE-MANAGER purl pkg:deb/debian/package-2@2.0.1
|
||||
##### Package: package-1
|
||||
|
||||
PackageName: package-1
|
||||
SPDXID: SPDXRef-Package-python-package-1-5a2b1ae000fcb51e
|
||||
SPDXID: SPDXRef-Package-python-package-1-fb6bef15e281ea43
|
||||
PackageVersion: 1.0.1
|
||||
PackageSupplier: NOASSERTION
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
@@ -51,7 +51,7 @@ ExternalRef: PACKAGE-MANAGER purl a-purl-2
|
||||
|
||||
##### Relationships
|
||||
|
||||
Relationship: SPDXRef-DocumentRoot-Directory-some-path CONTAINS SPDXRef-Package-python-package-1-5a2b1ae000fcb51e
|
||||
Relationship: SPDXRef-DocumentRoot-Directory-some-path CONTAINS SPDXRef-Package-python-package-1-fb6bef15e281ea43
|
||||
Relationship: SPDXRef-DocumentRoot-Directory-some-path CONTAINS SPDXRef-Package-deb-package-2-39392bb5e270f669
|
||||
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DocumentRoot-Directory-some-path
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ ExternalRef: PACKAGE-MANAGER purl pkg:deb/debian/package-2@2.0.1
|
||||
##### Package: package-1
|
||||
|
||||
PackageName: package-1
|
||||
SPDXID: SPDXRef-Package-python-package-1-c5cf7ac34cbca450
|
||||
SPDXID: SPDXRef-Package-python-package-1-80210ebcba92e632
|
||||
PackageVersion: 1.0.1
|
||||
PackageSupplier: NOASSERTION
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
@@ -54,7 +54,7 @@ ExternalRef: PACKAGE-MANAGER purl a-purl-1
|
||||
|
||||
##### Relationships
|
||||
|
||||
Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-python-package-1-c5cf7ac34cbca450
|
||||
Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-python-package-1-80210ebcba92e632
|
||||
Relationship: SPDXRef-DocumentRoot-Image-user-image-input CONTAINS SPDXRef-Package-deb-package-2-4b756c6f6fb127a3
|
||||
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DocumentRoot-Image-user-image-input
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"artifacts": [
|
||||
{
|
||||
"id": "5a2b1ae000fcb51e",
|
||||
"id": "fb6bef15e281ea43",
|
||||
"name": "package-1",
|
||||
"version": "1.0.1",
|
||||
"type": "python",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"artifacts": [
|
||||
{
|
||||
"id": "ad3ecac55fe1c30f",
|
||||
"id": "d748d4614750058d",
|
||||
"name": "package-1",
|
||||
"version": "1.0.1",
|
||||
"type": "python",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"artifacts": [
|
||||
{
|
||||
"id": "c5cf7ac34cbca450",
|
||||
"id": "80210ebcba92e632",
|
||||
"name": "package-1",
|
||||
"version": "1.0.1",
|
||||
"type": "python",
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -62,11 +61,11 @@ func NewFromUnindexedDirectoryFS(fs afero.Fs, dir string, base string) file.Writ
|
||||
}
|
||||
wd, err := os.Getwd()
|
||||
if err == nil {
|
||||
if !filepath.IsAbs(dir) {
|
||||
dir = filepath.Clean(filepath.Join(wd, dir))
|
||||
if !path.IsAbs(dir) {
|
||||
dir = path.Clean(path.Join(wd, dir))
|
||||
}
|
||||
if base != "" && !filepath.IsAbs(base) {
|
||||
base = filepath.Clean(filepath.Join(wd, base))
|
||||
if base != "" && !path.IsAbs(base) {
|
||||
base = path.Clean(path.Join(wd, base))
|
||||
}
|
||||
}
|
||||
return UnindexedDirectory{
|
||||
|
||||
@@ -29,7 +29,6 @@ func AllTypes() []any {
|
||||
pkg.JavaArchive{},
|
||||
pkg.LinuxKernel{},
|
||||
pkg.LinuxKernelModule{},
|
||||
pkg.LuaRocksPackage{},
|
||||
pkg.MicrosoftKbPatch{},
|
||||
pkg.NixStoreEntry{},
|
||||
pkg.NpmPackage{},
|
||||
|
||||
@@ -105,7 +105,6 @@ var jsonTypes = makeJSONTypes(
|
||||
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"),
|
||||
jsonNames(pkg.LuaRocksPackage{}, "luarocks-package"),
|
||||
)
|
||||
|
||||
func expandLegacyNameVariants(names ...string) []string {
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
package parsing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func IsWhitespace(c byte) bool {
|
||||
return unicode.IsSpace(rune(c))
|
||||
}
|
||||
|
||||
func IsLiteral(c byte) bool {
|
||||
r := rune(c)
|
||||
return unicode.IsNumber(r) || unicode.IsLetter(r) || r == '.' || r == '_'
|
||||
}
|
||||
|
||||
func SkipWhitespace(data []byte, i *int) {
|
||||
for *i < len(data) && IsWhitespace(data[*i]) {
|
||||
*i++
|
||||
}
|
||||
}
|
||||
|
||||
func PrintError(data []byte, i int) string {
|
||||
line := 1
|
||||
char := 1
|
||||
|
||||
prev := []string{}
|
||||
curr := bytes.Buffer{}
|
||||
|
||||
for idx, c := range data {
|
||||
if c == '\n' {
|
||||
prev = append(prev, curr.String())
|
||||
curr.Reset()
|
||||
|
||||
if idx >= i {
|
||||
break
|
||||
}
|
||||
|
||||
line++
|
||||
char = 1
|
||||
continue
|
||||
}
|
||||
if idx < i {
|
||||
char++
|
||||
}
|
||||
curr.WriteByte(c)
|
||||
}
|
||||
|
||||
l1 := fmt.Sprintf("%d", line-1)
|
||||
l2 := fmt.Sprintf("%d", line)
|
||||
|
||||
if len(l1) < len(l2) {
|
||||
l1 = " " + l1
|
||||
}
|
||||
|
||||
sep := ": "
|
||||
|
||||
lines := ""
|
||||
if len(prev) > 1 {
|
||||
lines += fmt.Sprintf("%s%s%s\n", l1, sep, prev[len(prev)-2])
|
||||
}
|
||||
if len(prev) > 0 {
|
||||
lines += fmt.Sprintf("%s%s%s\n", l2, sep, prev[len(prev)-1])
|
||||
}
|
||||
|
||||
pointer := strings.Repeat(" ", len(l2)+len(sep)+char-1) + "^"
|
||||
|
||||
return fmt.Sprintf("line: %v, char: %v\n%s%s", line, char, lines, pointer)
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/acobaugh/osrelease"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/anchore/go-logger"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
@@ -65,7 +64,25 @@ func IdentifyRelease(resolver file.Resolver) *Release {
|
||||
}
|
||||
|
||||
for _, location := range locations {
|
||||
release := tryParseReleaseInfo(resolver, location, logger, entry)
|
||||
contentReader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
logger.WithFields("error", err, "path", location.RealPath).Trace("unable to get contents")
|
||||
continue
|
||||
}
|
||||
|
||||
content, err := io.ReadAll(contentReader)
|
||||
internal.CloseAndLogError(contentReader, location.AccessPath)
|
||||
if err != nil {
|
||||
logger.WithFields("error", err, "path", location.RealPath).Trace("unable to read contents")
|
||||
continue
|
||||
}
|
||||
|
||||
release, err := entry.fn(string(content))
|
||||
if err != nil {
|
||||
logger.WithFields("error", err, "path", location.RealPath).Trace("unable to parse contents")
|
||||
continue
|
||||
}
|
||||
|
||||
if release != nil {
|
||||
return release
|
||||
}
|
||||
@@ -75,29 +92,6 @@ func IdentifyRelease(resolver file.Resolver) *Release {
|
||||
return nil
|
||||
}
|
||||
|
||||
func tryParseReleaseInfo(resolver file.Resolver, location file.Location, logger logger.Logger, entry parseEntry) *Release {
|
||||
contentReader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
logger.WithFields("error", err, "path", location.RealPath).Trace("unable to get contents")
|
||||
return nil
|
||||
}
|
||||
defer internal.CloseAndLogError(contentReader, location.AccessPath)
|
||||
|
||||
content, err := io.ReadAll(contentReader)
|
||||
if err != nil {
|
||||
logger.WithFields("error", err, "path", location.RealPath).Trace("unable to read contents")
|
||||
return nil
|
||||
}
|
||||
|
||||
release, err := entry.fn(string(content))
|
||||
if err != nil {
|
||||
logger.WithFields("error", err, "path", location.RealPath).Trace("unable to parse contents")
|
||||
return nil
|
||||
}
|
||||
|
||||
return release
|
||||
}
|
||||
|
||||
func parseOsRelease(contents string) (*Release, error) {
|
||||
values, err := osrelease.ReadString(contents)
|
||||
if err != nil {
|
||||
|
||||
@@ -27,8 +27,6 @@ type AlpmDBEntry struct {
|
||||
Reason int `mapstructure:"reason" json:"reason"`
|
||||
Files []AlpmFileRecord `mapstructure:"files" json:"files"`
|
||||
Backup []AlpmFileRecord `mapstructure:"backup" json:"backup"`
|
||||
Provides []string `mapstructure:"provides" json:"provides,omitempty"`
|
||||
Depends []string `mapstructure:"depends" json:"depends,omitempty"`
|
||||
}
|
||||
|
||||
type AlpmFileRecord struct {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user