mirror of
https://github.com/anchore/syft.git
synced 2026-10-13 14:47:22 +02:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4fc1af3b8 |
+1
-1
@@ -111,7 +111,7 @@ tools:
|
||||
# used for triggering a release
|
||||
- name: gh
|
||||
version:
|
||||
want: v2.48.0
|
||||
want: v2.47.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 }}
|
||||
|
||||
@@ -56,8 +56,6 @@ def main(changed_files: str | None = None, merge_base_schema_files: str | None =
|
||||
|
||||
pr_json_schema_files = filter_to_schema_files(pr_changed_files)
|
||||
|
||||
pr_labels = get_pr_labels(pr_number)
|
||||
|
||||
# print("schema files in pr: ", summarize_schema_files(pr_json_schema_files))
|
||||
# print("og schema files: ", summarize_schema_files(og_json_schema_files))
|
||||
|
||||
@@ -78,8 +76,7 @@ def main(changed_files: str | None = None, merge_base_schema_files: str | None =
|
||||
add_label(pr_number, JSON_SCHEMA_LABEL)
|
||||
|
||||
else:
|
||||
if JSON_SCHEMA_LABEL in pr_labels:
|
||||
remove_label(pr_number, JSON_SCHEMA_LABEL)
|
||||
remove_label(pr_number, JSON_SCHEMA_LABEL)
|
||||
|
||||
# new schema files should be scrutinized, comparing the latest and added versions to see if it's a breaking
|
||||
# change (major version bump). Warn about it on the PR via adding a breaking-change label...
|
||||
@@ -87,8 +84,7 @@ def main(changed_files: str | None = None, merge_base_schema_files: str | None =
|
||||
print("\nBreaking change detected...")
|
||||
add_label(pr_number, BREAKING_CHANGE_LABEL)
|
||||
else:
|
||||
if BREAKING_CHANGE_LABEL in pr_labels:
|
||||
remove_label(pr_number, BREAKING_CHANGE_LABEL)
|
||||
remove_label(pr_number, BREAKING_CHANGE_LABEL)
|
||||
|
||||
# modifying an existing schema could be a breaking change, we should warn about it on the PR via a comment...
|
||||
# removing schema files should never be allowed, we should warn about it on the PR via a comment...
|
||||
@@ -123,7 +119,7 @@ def add_label(pr_number: str, label: str):
|
||||
# run "gh pr edit --add-label <label>"
|
||||
result = run(f"gh pr edit {pr_number} --add-label {label}", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if result.returncode != 0:
|
||||
print(f"Unable to add '{label!r}' label to PR, error:")
|
||||
print(f"Unable to add {label!r} label to PR with")
|
||||
print(str(result.stderr))
|
||||
sys.exit(1)
|
||||
|
||||
@@ -132,7 +128,7 @@ def remove_label(pr_number: str, label: str):
|
||||
# run "gh pr edit --remove-label <label>"
|
||||
result = run(f"gh pr edit {pr_number} --remove-label {label}", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if result.returncode != 0:
|
||||
print(f"Unable to remove '{label!r}' label from PR, error:")
|
||||
print(f"Unable to label PR with {label!r}")
|
||||
print(str(result.stderr))
|
||||
sys.exit(1)
|
||||
|
||||
@@ -169,17 +165,6 @@ def get_pr_changed_files(pr_number: str) -> list[str]:
|
||||
return list_of_files
|
||||
|
||||
|
||||
def get_pr_labels(pr_number: str) -> list[str]:
|
||||
result = run(f"gh pr view {pr_number} --json labels --jq '.labels[].name'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
if result.returncode != 0:
|
||||
print("Unable to get list of labels on PR")
|
||||
print(str(result.stderr))
|
||||
sys.exit(1)
|
||||
|
||||
list_of_labels = result.stdout.splitlines()
|
||||
return list_of_labels
|
||||
|
||||
|
||||
def filter_to_schema_files(list_of_files: list[str]) -> list[str]:
|
||||
# get files matching "schema/json/schema-*.json"
|
||||
files = []
|
||||
|
||||
@@ -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@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
|
||||
echo "result=$OUTPUT" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
with:
|
||||
name: benchmark-test-results
|
||||
path: test/results/**/*
|
||||
|
||||
@@ -36,16 +36,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 #v5.0.1
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 #v5.0.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@ccf74c947955fd1cf117aef6a0e4e66191ef6f61 #v3.25.4
|
||||
uses: github/codeql-action/init@df5a14dc28094dc936e103b37d749c6628682b60 #v3.25.0
|
||||
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@ccf74c947955fd1cf117aef6a0e4e66191ef6f61 #v3.25.4
|
||||
uses: github/codeql-action/autobuild@df5a14dc28094dc936e103b37d749c6628682b60 #v3.25.0
|
||||
|
||||
# ℹ️ 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@ccf74c947955fd1cf117aef6a0e4e66191ef6f61 #v3.25.4
|
||||
uses: github/codeql-action/analyze@df5a14dc28094dc936e103b37d749c6628682b60 #v3.25.0
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- 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@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
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@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
|
||||
- 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@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- 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@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -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@7ccf588e3cf3cc2611714c2eeae48550fbc17552 #v0.15.11
|
||||
- uses: anchore/sbom-action@ab5d7b5f48981941c4c5d6bf33aeb98fe3bae38c #v0.15.10
|
||||
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@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
app_id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e #v6.0.5
|
||||
- uses: peter-evans/create-pull-request@c55203cfde3e5c11a452d352b4393e68b85b4533 #v6.0.3
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
app_id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e #v6.0.5
|
||||
- uses: peter-evans/create-pull-request@c55203cfde3e5c11a452d352b4393e68b85b4533 #v6.0.3
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
|
||||
@@ -17,9 +17,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 #v5.0.1
|
||||
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 #v5.0.0
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
stable: ${{ env.GO_STABLE_VERSION }}
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
app_id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e #v6.0.5
|
||||
- uses: peter-evans/create-pull-request@c55203cfde3e5c11a452d352b4393e68b85b4533 #v6.0.3
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
name: "Static analysis"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
name: "Unit tests"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
name: "Integration tests"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- 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@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- 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@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -187,7 +187,7 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -232,7 +232,7 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b #v4.1.5
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
@@ -49,18 +49,10 @@ linters-settings:
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 40
|
||||
statements: 50
|
||||
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".
|
||||
|
||||
@@ -92,7 +92,7 @@ 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://wiki.nixos.org/wiki/Nix_channels#The_official_channels) since NixOS `22.05`.
|
||||
**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
|
||||
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
<!-- Use this section to tell people about which versions of your project are
|
||||
currently being supported with security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 5.1.x | :white_check_mark: |
|
||||
| 5.0.x | :x: |
|
||||
| 4.0.x | :white_check_mark: |
|
||||
| < 4.0 | :x: |
|
||||
|
||||
-->
|
||||
|
||||
Security updates are applied only to the most recent release, try to always be up to date.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
<!-- Use this section to tell people how to report a vulnerability.
|
||||
|
||||
Tell them where to go, how often they can expect to get an update on a
|
||||
reported vulnerability, what to expect if the vulnerability is accepted or
|
||||
declined, etc. -->
|
||||
|
||||
To report a security issue, please email
|
||||
[security@anchore.com](mailto:security@anchore.com)
|
||||
with a description of the issue, the steps you took to create the issue,
|
||||
affected versions, and, if known, mitigations for the issue.
|
||||
|
||||
All support will be made on the best effort base, so please indicate the "urgency level" of the vulnerability as Critical, High, Medium or Low.
|
||||
@@ -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 #################################
|
||||
|
||||
|
||||
@@ -51,17 +51,17 @@ var noAssertion = map[string]string{
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar": "pkg:maven/sdk/sdk@3.0",
|
||||
|
||||
// syft generates incorrect purls
|
||||
"/packages/akka-actor_2.13-2.6.6.jar": "pkg:maven/com.typesafe.akka/akka-actor_2.13@2.6.6",
|
||||
"/packages/akka-management-cluster-bootstrap_2.13-1.2.0.jar": "pkg:maven/com.lightbend.akka.management/akka-management-cluster-bootstrap_2.13@1.2.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/asm-2.2.3.jar": "pkg:maven/asm/asm@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/asm-commons-2.2.3.jar": "pkg:maven/asm/asm-commons@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/asm-tree-2.2.3.jar": "pkg:maven/asm/asm-tree@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/slave.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3_min/xpp3_min@1.1.4c",
|
||||
"/packages/hudson.war:WEB-INF/lib/xpp3-1.1.4c.jar": "pkg:maven/xpp3/xpp3@1.1.4c",
|
||||
"/packages/hudson.war:WEB-INF/hudson-cli.jar": "pkg:maven/org.jvnet.hudson.main/hudson-cli@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/dom4j-1.6.1-hudson-3.jar": "pkg:maven/org.jvnet.hudson.dom4j/dom4j@1.6.1-hudson-3",
|
||||
"/packages/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3/xpp3_min@1.1.4c",
|
||||
//"/packages/akka-actor_2.13-2.6.6.jar": "pkg:maven/com.typesafe.akka/akka-actor_2.13@2.6.6",
|
||||
//"/packages/akka-management-cluster-bootstrap_2.13-1.2.0.jar": "pkg:maven/com.lightbend.akka.management/akka-management-cluster-bootstrap_2.13@1.2.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/asm-2.2.3.jar": "pkg:maven/asm/asm@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/asm-commons-2.2.3.jar": "pkg:maven/asm/asm-commons@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/asm-tree-2.2.3.jar": "pkg:maven/asm/asm-tree@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/slave.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3_min/xpp3_min@1.1.4c",
|
||||
"/packages/hudson.war:WEB-INF/lib/xpp3-1.1.4c.jar": "pkg:maven/xpp3/xpp3@1.1.4c",
|
||||
"/packages/hudson.war:WEB-INF/hudson-cli.jar": "pkg:maven/org.jvnet.hudson.main/hudson-cli@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/dom4j-1.6.1-hudson-3.jar": "pkg:maven/org.jvnet.hudson.dom4j/dom4j@1.6.1-hudson-3",
|
||||
"/packages/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3/xpp3_min@1.1.4c",
|
||||
|
||||
// syft generates an unstable purl
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-auth": "pkg:maven/org.apache.dubbo/dubbo-auth@3.1.4",
|
||||
@@ -113,27 +113,467 @@ var noAssertion = map[string]string{
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-xds": "pkg:maven/org.apache.dubbo/dubbo-xds@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
|
||||
|
||||
// TODO: Figure out newrelic stuff
|
||||
"/packages/newrelic-agent-8.8.0.jar:agent-bridge-datastore.jar": "pkg:maven/com.newrelic.agent.java/agent-bridge-datastore@8.8.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:agent-bridge.jar": "pkg:maven/com.newrelic.agent.java/agent-bridge@8.8.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-2.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-2.2/akka@2.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-2.11_2.4.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-2.11_2.4.5/akka-http@2.11_2.4.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-2.13_10.1.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-2.13_10.1.8/akka-http@2.13_10.1.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-core-0.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-core-0.4/akka-http-core@0.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-core-0.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-core-0.7/akka-http-core@0.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-core-1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-core-1.0/akka-http-core@1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-core-10.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-core-10.0/akka-http-core@10.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-core-10.2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-core-10.2.0/akka-http-core@10.2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-core-2.11_10.0.11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-core-10.0.11/akka-http-core@2.11_10.0.11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-core-2.13_10.1.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-core-2.13_10.1.8/akka-http-core@2.13_10.1.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/akka-http-core-2.13_10.2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.akka-http-core-2.13_10.2.0/akka-http-core@2.13_10.2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/anorm-2.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.anorm-2.3/anorm@2.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/anorm-2.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.anorm-2.4/anorm@2.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/apache-log4j-1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.apache-log4j-1/apache-log4j@1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/apache-log4j-2.11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.apache-log4j-2.11/apache-log4j@2.11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/apache-log4j-2.6-1.0.jar": "pkg:maven/com.newrelic.instrumentation.apache-log4j-2.6/apache-log4j@2.6-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/apache-struts-2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.apache-struts-2.0/apache-struts@2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/async-http-client-2.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.async-http-client-2.0.0/async-http-client@2.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/async-http-client-2.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.async-http-client-2.1.0/async-http-client@2.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/aws-java-sdk-dynamodb-1.11.106-1.0.jar": "pkg:maven/com.newrelic.instrumentation.aws-java-sdk-dynamodb-1.11.106/aws-java-sdk-dynamodb@1.11.106-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/aws-java-sdk-dynamodb-2.15.34-1.0.jar": "pkg:maven/com.newrelic.instrumentation.aws-java-sdk-dynamodb-2.15.34/aws-java-sdk-dynamodb@2.15.34-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/aws-java-sdk-s3-1.2.13-1.0.jar": "pkg:maven/com.newrelic.instrumentation.aws-java-sdk-s3-1.2.13/aws-java-sdk-s3@1.2.13-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/aws-java-sdk-s3-2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.aws-java-sdk-s3-2.0/aws-java-sdk-s3@2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/aws-java-sdk-sns-1.11.12-1.0.jar": "pkg:maven/com.newrelic.instrumentation.aws-java-sdk-sns/aws-java-sdk-sns@1.11.12-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/aws-java-sdk-sns-2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.aws-java-sdk-sns-2.0/aws-java-sdk-sns@2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/aws-java-sdk-sqs-1.10.44-1.0.jar": "pkg:maven/com.newrelic.instrumentation.aws-java-sdk-sqs-1.10.44/aws-java-sdk-sqs@1.10.44-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/aws-java-sdk-sqs-2.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.aws-java-sdk-sqs-2.1.0/aws-java-sdk-sqs@2.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/aws-wrap-0.7.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.aws-wrap-0.7.0/aws-wrap@0.7.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/cassandra-datastax-3.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.cassandra-datastax-3.0.0/cassandra-datastax@3.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/cassandra-datastax-3.8.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.cassandra-datastax-3.8.0/cassandra-datastax@3.8.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/cassandra-datastax-4.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.cassandra-datastax-4.0.0/cassandra-datastax@4.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/cats-effect-2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.cats-effect-2/cats-effect@2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/cats-effect-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.cats-effect-3/cats-effect@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/cats-effect-3.3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.cats-effect-3.3.0/cats-effect@3.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/cxf-2.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.cxf-2.7/cxf@2.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/ejb-3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.ejb-3.0/ejb@3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/ejb-4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.ejb-4.0/ejb@4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/glassfish-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.glassfish-3/glassfish@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/glassfish-6-1.0.jar": "pkg:maven/com.newrelic.instrumentation.glassfish-6/glassfish@6-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/glassfish-jmx-1.0.jar": "pkg:maven/com.newrelic.instrumentation.glassfish-jmx/glassfish-jmx@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/grails-1.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.grails-1.3/grails@1.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/grails-2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.grails-2/grails@2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/grails-async-2.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.grails-async-2.3/grails-async@2.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/graphql-java-16.2-1.0.jar": "pkg:maven/com.graphql-java/graphql-java@16.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/graphql-java-17.0-1.0.jar": "pkg:maven/com.graphql-java/graphql-java@17.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/graphql-java-21.0-1.0.jar": "pkg:maven/com.graphql-java/graphql-java@21.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/grpc-1.22.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.grpc-1.22.0/grpc@1.22.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/grpc-1.30.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.grpc-1.30.0/grpc@1.30.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/grpc-1.4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.grpc-1.4.0/grpc@1.4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/grpc-1.40.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.grpc-1.40.0/grpc@1.40.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/hibernate-3.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.hibernate-3.3/hibernate@3.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/hibernate-3.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.hibernate-3.5/hibernate@3.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/hibernate-4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.hibernate-4.0/hibernate@4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/hibernate-4.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.hibernate-4.2/hibernate@4.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/hibernate-4.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.hibernate-4.3/hibernate@4.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http-async-client-4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http-async-client-4/http-async-client@4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-client-2.12_0.21-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-client-2.12_0.21/http4s-blaze-client@2.12_0.21-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-client-2.12_0.22-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-client-2.12_0.22/http4s-blaze-client@2.12_0.22-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-client-2.12_0.23-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-client-2.12_0.23/http4s-blaze-client@2.12_0.23-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-client-2.13_0.21-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-client-2.13_0.21/http4s-blaze-client@2.13_0.21-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-client-2.13_0.22-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-client-2.13_0.22/http4s-blaze-client@2.13_0.22-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-client-2.13_0.23-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-client-2.13_0.23/http4s-blaze-client@2.13_0.23-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-server-2.12_0.21-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-server-2.12_0.21/http4s-blaze-server@2.12_0.21-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-server-2.12_0.22-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-server-2.12_0.22/http4s-blaze-server@2.12_0.22-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-server-2.12_0.23-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-server-2.12_0.23/http4s-blaze-server@2.12_0.23-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-server-2.13_0.21-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-server-2.13_0.21/http4s-blaze-server@2.13_0.21-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-server-2.13_0.22-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-server-2.13_0.22/http4s-blaze-server@2.13_0.22-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-blaze-server-2.13_0.23-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-blaze-server-2.13_0.23/http4s-blaze-server@2.13_0.23-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-ember-client-2.12_0.23-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-ember-client-2.12_0.23/http4s-ember-client@2.12_0.23-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-ember-client-2.13_0.23-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-ember-client-2.13_0.23/http4s-ember-client@2.13_0.23-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-ember-server-2.12_0.23-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-ember-server-2.12_0.23/http4s-ember-server@2.12_0.23-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/http4s-ember-server-2.13_0.23-1.0.jar": "pkg:maven/com.newrelic.instrumentation.http4s-ember-server-2.13_0.23/http4s-ember-server@2.13_0.23-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/httpclient-3.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.httpclient-3.1/httpclient@3.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/httpclient-4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.httpclient-4.0/httpclient@4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/httpclient-5.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.httpclient-5.0/httpclient@5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/httpclient-jdk11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.httpclient-jdk11/httpclient-jdk11@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/httpurlconnection-1.0.jar": "pkg:maven/com.newrelic.instrumentation.httpurlconnection/httpurlconnection@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/hystrix-1.3.15-1.0.jar": "pkg:maven/com.newrelic.instrumentation.hystrix-1.3.15/hystrix@1.3.15-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/hystrix-1.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.hystrix-1.4/hystrix@1.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jakarta.xml-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jakarta.xml/xml@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/java-io-1.0.jar": "pkg:maven/com.newrelic.instrumentation.java-io/java-io@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/java.completable-future-jdk8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.java.completable-future-jdk8/completable-future-jdk8@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/java.completable-future-jdk8u40-1.0.jar": "pkg:maven/com.newrelic.instrumentation.java.completable-future-jdk8u40/completable-future-jdk8u40@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/java.logging-jdk8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.java.logging-jdk8/logging-jdk8@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/javax.xml-1.0.jar": "pkg:maven/com.newrelic.instrumentation.javax.xml/xml@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jax-rs-1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jax-rs-1.0/jax-rs@1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jax-rs-3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jax-rs-3.0/jax-rs@3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jboss-7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jboss-7/jboss@7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jboss-jmx-7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jboss-jmx-7/jboss-jmx@7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jboss-logging-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jboss.logging/jboss-logging@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jcache-1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jcache-1.0.0/jcache@1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jcache-datastore-1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jcache-datastore-1.0.0/jcache-datastore@1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-db2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-db2/jdbc-db2@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-driver-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-driver/jdbc-driver@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-embedded-derby-10.11.1.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-embedded-derby-10.11.1.1/jdbc-embedded-derby@10.11.1.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-embedded-derby-10.15.1.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-embedded-derby-10.15.1.3/jdbc-embedded-derby@10.15.1.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-generic-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-generic/jdbc-generic@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-h2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-h2/jdbc-h2@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-hsqldb-1.7.2.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-hsqldb-1.7.2.2/jdbc-hsqldb@1.7.2.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-hsqldb-2.2.9-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-hsqldb-2.2.9/jdbc-hsqldb@2.2.9-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-inet-merlia-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-inet-merlia/jdbc-inet-merlia@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-inet-oranxo-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-inet-oranxo/jdbc-inet-oranxo@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-jtds-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-jtds/jdbc-jtds@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-jtds-generic-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-jtds-generic/jdbc-jtds-generic@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mariadb-1.1.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mariadb-1.1.7/jdbc-mariadb@1.1.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mariadb-1.3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mariadb-1.3.0/jdbc-mariadb@1.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mysql-3.0.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-3.0.8/jdbc-mysql@3.0.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mysql-6.0.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-6.0.2/jdbc-mysql@6.0.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mysql-8.0.11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-8.0.11/jdbc-mysql@8.0.11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mysql-connection-5.1.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-connection-5.1.4/jdbc-mysql-connection@5.1.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mysql-connection-6.0.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-connection-6.0.2/jdbc-mysql-connection@6.0.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mysql-connection-8.0.11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-connection-8.0.11/jdbc-mysql-connection@8.0.11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mysql-multihost-connections-5.1.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-multihost-connections-5.1.3/jdbc-mysql-multihost-connections@5.1.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mysql-multihost-connections-6.0.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-multihost-connections-6.0.2/jdbc-mysql-multihost-connections@6.0.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-mysql-multihost-connections-8.0.11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-multihost-connections-8.0.11/jdbc-mysql-multihost-connections@8.0.11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-ojdbc-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-ojdbc/jdbc-ojdbc@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-ojdbc-tns-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-ojdbc-tns/jdbc-ojdbc-tns@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-ojdbc7-12.1.0.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-ojdbc7-12.1.0.2/jdbc-ojdbc7@12.1.0.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-ojdbc8-21.1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-ojdbc8-21.1.0.0/jdbc-ojdbc8@21.1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-postgresql-8.0-312.jdbc3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-postgresql-8.0-312.jdbc3/jdbc-postgresql@8.0-312.jdbc3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-postgresql-9.4.1207-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-postgresql-9.4.1207/jdbc-postgresql@9.4.1207-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-postgresql-9.4.1208-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-postgresql-9.4.1208/jdbc-postgresql@9.4.1208-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-resultset-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-resultset/jdbc-resultset@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-socket-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-socket/jdbc-socket@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-socket-jdk21-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-socket-jdk21/jdbc-socket-jdk21@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-sqlserver-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-sqlserver/jdbc-sqlserver@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jdbc-sybase-6-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-sybase-6/jdbc-sybase@6-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jedis-1.4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jedis-1.4.0/jedis@1.4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jedis-2.7.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jedis-2.7.1/jedis@2.7.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jedis-2.7.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jedis-2.7.2/jedis@2.7.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jedis-3.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jedis-3.0.0/jedis@3.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jedis-4.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jedis-4.0.0/jedis@4.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jersey-1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jersey-1/jersey@1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jersey-2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jersey-2/jersey@2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jersey-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jersey-3/jersey@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jersey-client-1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jersey-client-1/jersey-client@1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jersey-client-2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jersey-client-2/jersey-client@2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jersey-client-2.26-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jersey-client-2.26/jersey-client@2.26-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jersey-client-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jersey-client-3/jersey-client@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-10-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-10/jetty@10-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-11/jetty@11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-12-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-12/jetty@12-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-9.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-9.3/jetty@9.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-ee10-servlet-12-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-ee10-servlet-12/jetty-ee10-servlet@12-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-ee10-servlet-12.0.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-ee10-servlet-12.0.1/jetty-ee10-servlet@12.0.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-ee8-servlet-12-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-ee8-servlet-12/jetty-ee8-servlet@12-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-ee9-servlet-12-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-ee9-servlet-12/jetty-ee9-servlet@12-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-jmx-7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-jmx-7/jetty-jmx@7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jetty-servlet-9-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jetty-servlet-9/jetty-servlet@9-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jms-1.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jms-1.1/jms@1.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jms-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jms-3/jms@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jsp-2.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jsp-2.4/jsp@2.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/jsp-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jsp-3/jsp@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-clients-config-1.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-clients-config-1.1.0/kafka-clients-config@1.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-clients-heartbeat-0.10.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-clients-heartbeat-0.10.1.0/kafka-clients-heartbeat@0.10.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-clients-heartbeat-2.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-clients-heartbeat-2.1.0/kafka-clients-heartbeat@2.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-clients-metrics-0.10.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-clients-metrics-0.10.0.0/kafka-clients-metrics@0.10.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-clients-metrics-2.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-clients-metrics-2.0.0/kafka-clients-metrics@2.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-clients-metrics-3.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-clients-metrics-3.0.0/kafka-clients-metrics@3.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-clients-node-metrics-1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-clients-node-metrics-1.0.0/kafka-clients-node-metrics@1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-clients-spans-0.11.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-clients-spans-0.11.0.0/kafka-clients-spans@0.11.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-connect-metrics-1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-connect-metrics-1.0.0/kafka-connect-metrics@1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-connect-spans-2.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-connect-spans-2.0.0/kafka-connect-spans@2.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-connect-spans-3.3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-connect-spans-3.3.0/kafka-connect-spans@3.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-streams-metrics-1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-streams-metrics-1.0.0/kafka-streams-metrics@1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-streams-spans-2.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-streams-spans-2.0.0/kafka-streams-spans@2.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-streams-spans-2.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-streams-spans-2.1.0/kafka-streams-spans@2.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-streams-spans-2.6.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-streams-spans-2.6.0/kafka-streams-spans@2.6.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/kafka-streams-spans-3.2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.kafka-streams-spans-3.2.0/kafka-streams-spans@3.2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/lettuce-4.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.lettuce-4.3/lettuce@4.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/lettuce-5.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.lettuce-5.0/lettuce@5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/lettuce-6.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.lettuce-6.0/lettuce@6.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/logback-classic-1.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.logback-classic-1.2/logback-classic@1.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-3.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-3.1/mongodb@3.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-3.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-3.7/mongodb@3.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-async-3.10-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-async-3.10/mongodb-async@3.10-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-async-3.11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-async-3.11/mongodb-async@3.11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-async-3.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-async-3.4/mongodb-async@3.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-async-3.6-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-async-3.6/mongodb-async@3.6-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-async-3.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-async-3.7/mongodb-async@3.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-async-3.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-async-3.8/mongodb-async@3.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-async-4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-async-4.0/mongodb-async@4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-reactive-streams-4.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-reactive-streams-4.2/mongodb-reactive-streams@4.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mongodb-reactive-streams-4.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mongodb-reactive-streams-4.8/mongodb-reactive-streams@4.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/monix-2.13_3.4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.monix-2.13_3.4.0/monix@2.13_3.4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mule-3.6-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mule-3.6/mule@3.6-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mule-3.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mule-3.7/mule@3.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mule-base-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mule-base/mule-base@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mule-ei1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mule-ei1/mule-ei1@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/mule-ei2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.mule-ei2/mule-ei2@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/netty-3.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.netty-3.4/netty@3.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/netty-3.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.netty-3.8/netty@3.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/netty-4.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.netty-4.0.0/netty@4.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/netty-4.0.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.netty-4.0.8/netty@4.0.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/netty-reactor-0.7.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.netty-reactor-0.7.0/netty-reactor@0.7.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/netty-reactor-0.8.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.netty-reactor-0.8.0/netty-reactor@0.8.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/netty-reactor-0.9.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.netty-reactor-0.9.0/netty-reactor@0.9.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/newrelic-cats-effect3-api-1.0.jar": "pkg:maven/com.newrelic.instrumentation.newrelic-cats-effect3-api/newrelic-cats-effect3-api@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/newrelic-scala-cats-api-1.0.jar": "pkg:maven/com.newrelic.instrumentation.newrelic-scala-cats-api/newrelic-scala-cats-api@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/newrelic-scala-monix-api-1.0.jar": "pkg:maven/com.newrelic.instrumentation.scala-monix-api/newrelic-scala-monix-api@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/newrelic-scala-zio-api-1.0.jar": "pkg:maven/com.newrelic.instrumentation.newrelic-scala-zio-api/newrelic-scala-zio-api@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/ning-async-http-client-1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.ning-async-http-client-1.0/ning-async-http-client@1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/ning-async-http-client-1.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.ning-async-http-client-1.1/ning-async-http-client@1.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/ning-async-http-client-1.6.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.ning-async-http-client-1.6.1/ning-async-http-client@1.6.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/okhttp-3.14.0-1.0.jar": "pkg:maven/com.squareup.okhttp3/okhttp@3.14.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/okhttp-3.6.0-1.0.jar": "pkg:maven/com.squareup.okhttp3/okhttp@3.6.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/okhttp-4.0.0-1.0.jar": "pkg:maven/com.squareup.okhttp3/okhttp@4.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/okhttp-4.4.0-1.0.jar": "pkg:maven/com.squareup.okhttp3/okhttp@4.4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/open-liberty-jakarta-21.0.0.12-1.0.jar": "pkg:maven/com.newrelic.instrumentation.open-liberty-jakarta-21.0.0.12/open-liberty-jakarta@21.0.0.12-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/openejb-3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.openejb-3.0/openejb@3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/openjpa-1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.openjpa-1.0.0/openjpa@1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/oracle-r2dbc-1.0.jar": "pkg:maven/com.newrelic.instrumentation.oracle-r2dbc/oracle-r2dbc@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-2.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-2.3/play@2.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-2.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-2.4/play@2.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-2.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-2.5/play@2.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-2.6-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-2.6/play@2.6-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-2.6.13-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-2.6.13/play@2.6.13-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-2.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-2.7/play@2.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-2.8.16-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-2.8.16/play@2.8.16-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-shaded-async-http-client-1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-shaded-async-http-client-1.0.0/play-shaded-async-http-client@1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-ws-2.13_2.6.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-ws-2.13_2.6.0/play-ws@2.13_2.6.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/play-ws-2.6.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.play-ws-2.6.0/play-ws@2.6.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/quartz-1.8.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.quartz-1.8.3/quartz@1.8.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/quartz-2.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.quartz-2.0.0/quartz@2.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/r2dbc-h2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.r2dbc-h2/r2dbc-h2@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/r2dbc-mariadb-1.0.jar": "pkg:maven/com.newrelic.instrumentation.r2dbc-mariadb/r2dbc-mariadb@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/r2dbc-mssql-1.0.jar": "pkg:maven/com.newrelic.instrumentation.r2dbc-mssql/r2dbc-mssql@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/r2dbc-mysql-1.0.jar": "pkg:maven/com.newrelic.instrumentation.r2dbc-mysql/r2dbc-mysql@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/r2dbc-postgresql-0.9.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.r2dbc-postgresql-0.9.0/r2dbc-postgresql@0.9.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/r2dbc-postgresql-0.9.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.r2dbc-postgresql-0.9.2/r2dbc-postgresql@0.9.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/rabbit-amqp-2.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.rabbit-amqp-2.7/rabbit-amqp@2.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/rabbit-amqp-3.5.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.rabbit-amqp-3.5.0/rabbit-amqp@3.5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/rabbit-amqp-5.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.rabbit-amqp-5.0.0/rabbit-amqp@5.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/reactor-3.3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.reactor-3.3.0/reactor@3.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/resin-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.resin-3/resin@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/resin-4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.resin-4/resin@4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/resin-jmx-1.0.jar": "pkg:maven/com.newrelic.instrumentation.resin-jmx/resin-jmx@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/resteasy-2.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.resteasy-2.2/resteasy@2.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/resteasy-3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.resteasy-3.0/resteasy@3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/scala-2.12.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.scala-2.12.0/scala@2.12.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/scala-2.13.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.scala-2.13.0/scala@2.13.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/scala-2.9.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.scala-2.9.3/scala@2.9.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/servlet-2.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.servlet-2.4/servlet@2.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/servlet-5.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.servlet-5.0/servlet@5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/servlet-6.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.servlet-6.0/servlet@6.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/servlet-user-1.0.jar": "pkg:maven/com.newrelic.instrumentation.servlet-user/servlet-user@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/servlet-user-5.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.servlet-user-5.0/servlet-user@5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/slick-2.11_3.2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.slick-2.11_3.2.0/slick@2.11_3.2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/slick-2.12_3.2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.slick-2.12_3.2.0/slick@2.12_3.2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/slick-3.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.slick-3.0.0/slick@3.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/solr-4.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.solr-4.0.0/solr@4.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/solr-5.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.solr-5.0.0/solr@5.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/solr-5.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.solr-5.1.0/solr@5.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/solr-5.4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.solr-5.4.0/solr@5.4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/solr-6.4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.solr-6.4.0/solr@6.4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/solr-7.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.solr-7.0.0/solr@7.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/solr-jmx-7.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.solr-jmx-7.0.0/solr-jmx@7.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/solr-jmx-7.4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.solr-jmx-7.4.0/solr-jmx@7.4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spray-can-1.3.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.spray-can-1.3.1/spray-can@1.3.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spray-can-http-client-1.3.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.spray-can-http-client-1.3.1/spray-can-http-client@1.3.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spray-client-1.3.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.spray-client-1.3.1/spray-client@1.3.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spray-http-1.3.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.spray-http-1.3.1/spray-http@1.3.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-3.0.0-1.0.jar": "pkg:maven/org.springframework/spring@3.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-4.0.0-1.0.jar": "pkg:maven/org.springframework/spring@4.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-4.2.0-1.0.jar": "pkg:maven/org.springframework/spring@4.2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-4.3.0-1.0.jar": "pkg:maven/org.springframework/spring@4.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-aop-2-1.0.jar": "pkg:maven/org.springframework/spring-aop@2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-cache-3.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.spring-cache-3.1.0/spring-cache@3.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-jms-2-1.0.jar": "pkg:maven/org.springframework/spring-jms@2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-jms-3-1.0.jar": "pkg:maven/org.springframework/spring-jms@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-webclient-5.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.spring-webclient-5.0/spring-webclient@5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-webflux-5.0.0-1.0.jar": "pkg:maven/org.springframework/spring-webflux@5.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-webflux-5.1.0-1.0.jar": "pkg:maven/org.springframework/spring-webflux@5.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-webflux-5.3.0-1.0.jar": "pkg:maven/org.springframework/spring-webflux@5.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-webflux-6.0.0-1.0.jar": "pkg:maven/org.springframework/spring-webflux@6.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spring-ws-2.0-1.0.jar": "pkg:maven/org.springframework.ws/spring-ws@2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/spymemcached-2.12.0-1.0.jar": "pkg:maven/com.newrelic/spymemcached@2.12.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sttp-2.12_2.2.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sttp-2.12_2.2.3/sttp@2.12_2.2.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sttp-2.13_2.2.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sttp-2.13_2.2.3/sttp@2.13_2.2.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sttp-2.13_3.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sttp-2.13_3.0.0/sttp@2.13_3.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sttp-akka-2.12_2.1.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sttp-akka-2.12_2.1.5/sttp-akka@2.12_2.1.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sttp-akka-2.13_2.1.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sttp-akka-2.13_2.1.5/sttp-akka@2.13_2.1.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sttp-akka-2.13_3.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sttp-akka-2.13_3.0.0/sttp-akka@2.13_3.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sttp-http4s-2.12_2.1.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sttp-http4s-2.12_2.1.5/sttp-http4s@2.12_2.1.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sttp-http4s-2.13_2.1.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sttp-http4s-2.13_2.1.5/sttp-http4s@2.13_2.1.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sttp-http4s-2.13_3.3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sttp-http4s-2.13_3.3.0/sttp-http4s@2.13_3.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/sun-net-httpserver-1.0.jar": "pkg:maven/com.newrelic.instrumentation.sun-net-httpserver/sun-net-httpserver@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/thrift-0.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.thrift-0.8/thrift@0.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/tomcat-10-1.0.jar": "pkg:maven/org.apache.tomcat/tomcat@10-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/tomcat-7-1.0.jar": "pkg:maven/org.apache.tomcat/tomcat@7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/tomcat-7.0.70-1.0.jar": "pkg:maven/org.apache.tomcat/tomcat@7.0.70-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/tomcat-8.5.0-1.0.jar": "pkg:maven/org.apache.tomcat/tomcat@8.5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/tomcat-8.5.2-1.0.jar": "pkg:maven/org.apache.tomcat/tomcat@8.5.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/tomcat-jmx-1.0.jar": "pkg:maven/com.newrelic.instrumentation.tomcat-jmx/tomcat-jmx@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/tomcat-request-listener-1.0.jar": "pkg:maven/com.newrelic.instrumentation.tomcat-request-listener/tomcat-request-listener@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/tomcat-request-listener-10-1.0.jar": "pkg:maven/com.newrelic.instrumentation.tomcat-request-listener-10/tomcat-request-listener@10-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-core-3.3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-core-3.3.0/vertx-core@3.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-core-3.3.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-core-3.3.3/vertx-core@3.3.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-core-3.4.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-core-3.4.1/vertx-core@3.4.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-core-3.6.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-core-3.6.0/vertx-core@3.6.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-core-3.8.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-core-3.8.0/vertx-core@3.8.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-core-3.9.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-core-3.9.0/vertx-core@3.9.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-core-4.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-core-4.0.0/vertx-core@4.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-core-4.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-core-4.1.0/vertx-core@4.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-core-4.3.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-core-4.3.2/vertx-core@4.3.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-web-3.2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-web-3.2.0/vertx-web@3.2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-web-3.3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-web-3.3.0/vertx-web@3.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-web-3.5.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-web-3.5.0/vertx-web@3.5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-web-3.5.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-web-3.5.1/vertx-web@3.5.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-web-3.5.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-web-3.5.2/vertx-web@3.5.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-web-3.6.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-web-3.6.0/vertx-web@3.6.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-web-3.8.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-web-3.8.0/vertx-web@3.8.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/vertx-web-3.8.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.vertx-web-3.8.3/vertx-web@3.8.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/weblogic-12-1.0.jar": "pkg:maven/com.newrelic.instrumentation.weblogic-12/weblogic@12-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/weblogic-12.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.weblogic-12.2/weblogic@12.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/weblogic-jmx-12-1.0.jar": "pkg:maven/com.newrelic.instrumentation.weblogic-jmx-12/weblogic-jmx@12-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/weblogic-jmx-12.2.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.weblogic-jmx-12.2.1/weblogic-jmx@12.2.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/websphere-8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.websphere-8/websphere@8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/websphere-jmx-7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.websphere-jmx-7/websphere-jmx@7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/websphere-liberty-profile-8.5.5.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.websphere-liberty-profile-8.5.5.5/websphere-liberty-profile@8.5.5.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/websphere-liberty-profile-dispatcher-8.5.5.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.websphere-liberty-profile-dispatcher-8.5.5.5/websphere-liberty-profile-dispatcher@8.5.5.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/websphere-liberty-profile-environment-8.5.5.5-1.0.jar": "pkg:maven/com.newrelic.instrumentation.websphere-liberty-profile-environment-8.5.5.5/websphere-liberty-profile-environment@8.5.5.5-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/wildfly-27-1.0.jar": "pkg:maven/com.newrelic.instrumentation.wildfly-27/wildfly@27-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/wildfly-8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.wildfly-8/wildfly@8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/wildfly-8-CAT-1.0.jar": "pkg:maven/com.newrelic.instrumentation.wildfly-8-CAT/wildfly@8-CAT-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/wildfly-8-PORT-1.0.jar": "pkg:maven/com.newrelic.instrumentation.wildfly-8-PORT/wildfly@8-PORT-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/wildfly-jmx-14-1.0.jar": "pkg:maven/com.newrelic.instrumentation.wildfly-jmx-14/wildfly-jmx@14-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:instrumentation/zio-1.0.jar": "pkg:maven/com.newrelic.instrumentation.zio/zio@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-api.jar": "pkg:maven/newrelic-api/newrelic-api@8.8.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/akka-http-core-10.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.akka-http-core-10.0/akka-http-core@10.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/akka-http-core-2.11_10.0.11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.akka-http-core-10.0.11/akka-http-core@2.11_10.0.11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/apache-ldap-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.apache-ldap/apache-ldap@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/apache-log4j-2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.apache-log4j-2.0/apache-log4j@2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/apache-log4j-2.17.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.apache-log4j/apache-log4j@2.17.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/apache-log4j-3.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.apache-log4j/apache-log4j@3.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/async-http-client-2.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.async-http-client-2.0.0/async-http-client@2.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/camel-xpath-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.camel-xpath/camel-xpath@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/cassandra-datastax-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.cassandra-datastax-3/cassandra-datastax@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/cassandra-datastax-4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.cassandra-datastax-4/cassandra-datastax@4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/commons-jxpath-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.commons-jxpath/commons-jxpath@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/dynamodb-1.11.390-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.dynamodb-1.11.390/dynamodb@1.11.390-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/dynamodb-1.11.453-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.dynamodb-1.11.453/dynamodb@1.11.453-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/dynamodb-1.11.459-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.dynamodb-1.11.459/dynamodb@1.11.459-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/dynamodb-1.11.80-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.dynamodb-1.11.80/dynamodb@1.11.80-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/dynamodb-2.1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.dynamodb-2.1.0/dynamodb@2.1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/dynamodb-2.1.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.dynamodb-2.1.2/dynamodb@2.1.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/dynamodb-2.15.34-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.dynamodb-2.15.34/dynamodb@2.15.34-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/file-operation-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.file-operation/file-operation@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/graalvm-jsinjection-19.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.graalvm-jsinjection-19.0.0/graalvm-jsinjection@19.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/graalvm-jsinjection-22.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.graalvm-jsinjection-22.0.0/graalvm-jsinjection@22.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/http-async-client-4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.http-async-client-4/http-async-client@4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/httpclient-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.httpclient-3/httpclient@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/httpclient-4.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.httpclient-4.0/httpclient@4.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/httpclient-5.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.httpclient-5.0/httpclient@5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/httpclient-jdk11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.httpclient-jdk11/httpclient-jdk11@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/java-io-inputstream-jdk8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.java-io-inputstream-jdk8/java-io-inputstream-jdk8@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/java-io-inputstream-jdk9-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.java-io-inputstream-jdk9/java-io-inputstream-jdk9@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/java-io-stream-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.java-io-stream/java-io-stream@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/java-lang-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.java-lang/java-lang@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/javax-jndi-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.javax-jndi/javax-jndi@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/javax-ldap-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.javax-ldap/javax-ldap@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/javax-xpath-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.javax-xpath/javax-xpath@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jax-rs-1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jax-rs-1.0/jax-rs@1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jax-rs-3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jax-rs-3.0/jax-rs@3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jaxen-xpath-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jaxen-xpath/jaxen-xpath@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jaxen-xpath-1.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jaxen-xpath-1.1/jaxen-xpath@1.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-db2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-db2/jdbc-db2@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-embedded-derby-10.10.1.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-embedded-derby-10.10.1.1/jdbc-embedded-derby@10.10.1.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-embedded-derby-10.11.1.1-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-embedded-derby-10.11.1.1/jdbc-embedded-derby@10.11.1.1-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-embedded-derby-10.15.1.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-embedded-derby-10.15.1.3/jdbc-embedded-derby@10.15.1.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-embedded-derby-10.2.1.6-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-embedded-derby-10.2.1.6/jdbc-embedded-derby@10.2.1.6-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-generic-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-generic/jdbc-generic@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-h2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-h2/jdbc-h2@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-hsqldb-1.7.2.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-hsqldb-1.7.2.2/jdbc-hsqldb@1.7.2.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-hsqldb-2.2.9-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-hsqldb-2.2.9/jdbc-hsqldb@2.2.9-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-inet-merlia-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-inet-merlia/jdbc-inet-merlia@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-inet-oranxo-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-inet-merlia/jdbc-inet-oranxo@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-jtds-generic-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-jtds-generic/jdbc-jtds-generic@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mariadb-1.1.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-mariadb-1.1.7/jdbc-mariadb@1.1.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mariadb-1.3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-mariadb-1.3.0/jdbc-mariadb@1.3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mysql-3.0.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-mysql-3.0.8/jdbc-mysql@3.0.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mysql-6.0.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-mysql-6.0.2/jdbc-mysql@6.0.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mysql-6.0.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-mysql-6.0.4/jdbc-mysql@6.0.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mysql-8.0.11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-mysql-8.0.11/jdbc-mysql@8.0.11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mysql-connection-5.1.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-mysql-connection-5.1.4/jdbc-mysql-connection@5.1.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mysql-connection-6.0.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-mysql-connection-6.0.2/jdbc-mysql-connection@6.0.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mysql-connection-8.0.11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-mysql-connection-8.0.11/jdbc-mysql-connection@8.0.11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mysql-multihost-connections-5.1.3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-multihost-connections-5.1.3/jdbc-mysql-multihost-connections@5.1.3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-mysql-multihost-connections-6.0.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.jdbc-mysql-multihost-connections-6.0.2/jdbc-mysql-multihost-connections@6.0.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-ojdbc-tns-12.1.0.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-ojdbc-tns/jdbc-ojdbc-tns@12.1.0.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-ojdbc-tns-21.1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-ojdbc-tns-21.1.0.0/jdbc-ojdbc-tns@21.1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-ojdbc-tns-21.6.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-ojdbc-tns-21.6.0.0/jdbc-ojdbc-tns@21.6.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-ojdbc7-12.1.0.2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-ojdbc7-12.1.0.2/jdbc-ojdbc7@12.1.0.2-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-ojdbc8-21.1.0.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-ojdbc8-21.1.0.0/jdbc-ojdbc8@21.1.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-postgresql-8.0-312.jdbc3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-postgresql-8.0-312.jdbc3/jdbc-postgresql@8.0-312.jdbc3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-postgresql-9.4.1207-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-postgresql-9.4.1207/jdbc-postgresql@9.4.1207-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-postgresql-9.4.1208-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-postgresql-9.4.1208/jdbc-postgresql@9.4.1208-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-sqlserver-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-sqlserver/jdbc-sqlserver@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jdbc-sybase-6-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jdbc-sybase-6/jdbc-sybase@6-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jetty-11-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jetty-11/jetty@11-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jetty-9-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jetty-9/jetty@9-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jsp-2.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jsp-2.4/jsp@2.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/jsp-3-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.jsp-3/jsp@3-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/ldaptive-1.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.ldaptive-1.0/ldaptive@1.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/ldaptive-2.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.ldaptive-2.0/ldaptive@2.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/low-priority-instrumentation-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.low-priority-instrumentation/low-priority-instrumentation@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/mongodb-3.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.mongodb-3.0/mongodb@3.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/mongodb-3.6-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.mongodb-3.6/mongodb@3.6-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/mongodb-3.7-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.mongodb-3.7/mongodb@3.7-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/mongodb-3.8-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.mongodb-3.8/mongodb@3.8-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/nashorn-jsinjection-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.nashorn-jsinjection/nashorn-jsinjection@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/okhttp-3.0.0-1.0.jar": "pkg:maven/com.squareup.okhttp3/okhttp@3.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/okhttp-3.5.0-1.0.jar": "pkg:maven/com.squareup.okhttp3/okhttp@3.5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/okhttp-4.0.0-1.0.jar": "pkg:maven/com.squareup.okhttp3/okhttp@4.0.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/r2dbc-generic-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.r2dbc-generic/r2dbc-generic@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/r2dbc-h2-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.r2dbc-h2/r2dbc-h2@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/r2dbc-mariadb-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.r2dbc-mariadb/r2dbc-mariadb@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/r2dbc-mssql-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.r2dbc-mssql/r2dbc-mssql@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/r2dbc-mysql-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.r2dbc-mysql/r2dbc-mysql@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/r2dbc-oracle-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.r2dbc-oracle/r2dbc-oracle@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/r2dbc-postgresql-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.r2dbc-postgresql/r2dbc-postgresql@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/rhino-jsinjection-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.rhino-jsinjection/rhino-jsinjection@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/saxpath-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.saxpath/saxpath@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/servlet-2.4-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.servlet-2.4/servlet@2.4-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/servlet-5.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.servlet-5.0/servlet@5.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/servlet-6.0-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.servlet-6.0/servlet@6.0-1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/spring-web-1.0.jar": "pkg:maven/org.springframework/spring-web@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/sun-net-httpserver-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.sun-net-httpserver/sun-net-httpserver@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/unboundid-ldapsdk-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.unboundid-ldapsdk/unboundid-ldapsdk@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/urlconnection-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.urlconnection/urlconnection@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar:instrumentation-security/xalan-xpath-1.0.jar": "pkg:maven/com.newrelic.instrumentation.security.xalan-xpath/xalan-xpath@1.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-agent.jar": "pkg:maven/com.newrelic.agent.java.security/newrelic-security-agent@1.0.7-public-preview",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-security-api.jar": "pkg:maven/com.newrelic.agent.java.security/newrelic-security-api@1.0.7-public-preview",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-weaver-api.jar": "pkg:maven/com.newrelic.agent.java/newrelic-weaver-api@8.8.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar:newrelic-weaver-scala-api.jar": "pkg:maven/com.newrelic.agent.java/newrelic-weaver-scala-api@8.8.0",
|
||||
"/packages/newrelic-agent-8.8.0.jar": "pkg:maven/com.newrelic.agent.java/newrelic-agent@8.8.0",
|
||||
}
|
||||
|
||||
// Constructed by:
|
||||
// syft anchore/test_images:java-1abc58f -o json | jq -r '.artifacts.[] | [.metadata.virtualPath, .purl, ""] | @csv' | grep 'pkg:maven' | sort | uniq >> /tmp/java_artifacts_mapping.txt
|
||||
// The map was then hand-edited for correctness by comparing to Maven Central.
|
||||
var expectedPURLs = map[string]string{
|
||||
"/packages/activemq-client-5.18.2.jar": "pkg:maven/org.apache.activemq/activemq-client@5.18.2",
|
||||
"/packages/activemq-protobuf-1.1.jar": "pkg:maven/org.apache.activemq.protobuf/activemq-protobuf@1.1",
|
||||
// "/packages/akka-actor_2.13-2.6.6.jar": "pkg:maven/com.typesafe.akka/akka-actor_2.13@2.6.6",
|
||||
// "/packages/akka-management-cluster-bootstrap_2.13-1.2.0.jar": "pkg:maven/com.lightbend.akka.management/akka-management-cluster-bootstrap_2.13@1.2.0",
|
||||
"/packages/ant-1.10.3.jar": "pkg:maven/org.apache.ant/ant@1.10.3",
|
||||
"/packages/apache-chainsaw-2.1.0.jar": "pkg:maven/log4j/apache-chainsaw@2.1.0",
|
||||
"/packages/apache-log4j-extras-1.1.jar": "pkg:maven/log4j/apache-log4j-extras@1.1",
|
||||
"/packages/apoc-4.4.0.11.jar": "pkg:maven/org.neo4j.procedure/apoc@4.4.0.11",
|
||||
"/packages/bc-fips-1.0.2.3.jar": "pkg:maven/org.bouncycastle/bc-fips@1.0.2.3",
|
||||
"/packages/camel-core-3.1.0.jar": "pkg:maven/org.apache.camel/camel-core@3.1.0",
|
||||
"/packages/cassandra-all-4.1.1.jar": "pkg:maven/org.apache.cassandra/cassandra-all@4.1.1",
|
||||
"/packages/commons-logging-1.1.1.jar": "pkg:maven/commons-logging/commons-logging@1.1.1",
|
||||
"/packages/commons-vfs-1.0.jar": "pkg:maven/commons-vfs/commons-vfs@1.0",
|
||||
"/packages/cxf-rt-transports-http-2.7.3.jar": "pkg:maven/org.apache.cxf/cxf-rt-transports-http@2.7.3",
|
||||
"/packages/dubbo-3.1.4.jar:com.alibaba:hessian-lite": "pkg:maven/com.alibaba/hessian-lite@3.2.13",
|
||||
"/packages/activemq-client-5.18.2.jar": "pkg:maven/org.apache.activemq/activemq-client@5.18.2",
|
||||
"/packages/activemq-protobuf-1.1.jar": "pkg:maven/org.apache.activemq.protobuf/activemq-protobuf@1.1",
|
||||
"/packages/akka-actor_2.13-2.6.6.jar": "pkg:maven/com.typesafe.akka/akka-actor_2.13@2.6.6",
|
||||
"/packages/akka-management-cluster-bootstrap_2.13-1.2.0.jar": "pkg:maven/com.lightbend.akka.management/akka-management-cluster-bootstrap_2.13@1.2.0",
|
||||
"/packages/ant-1.10.3.jar": "pkg:maven/org.apache.ant/ant@1.10.3",
|
||||
"/packages/apache-chainsaw-2.1.0.jar": "pkg:maven/log4j/apache-chainsaw@2.1.0",
|
||||
"/packages/apache-log4j-extras-1.1.jar": "pkg:maven/log4j/apache-log4j-extras@1.1",
|
||||
"/packages/apoc-4.4.0.11.jar": "pkg:maven/org.neo4j.procedure/apoc@4.4.0.11",
|
||||
"/packages/bc-fips-1.0.2.3.jar": "pkg:maven/org.bouncycastle/bc-fips@1.0.2.3",
|
||||
"/packages/camel-core-3.1.0.jar": "pkg:maven/org.apache.camel/camel-core@3.1.0",
|
||||
"/packages/cassandra-all-4.1.1.jar": "pkg:maven/org.apache.cassandra/cassandra-all@4.1.1",
|
||||
"/packages/commons-logging-1.1.1.jar": "pkg:maven/commons-logging/commons-logging@1.1.1",
|
||||
"/packages/commons-vfs-1.0.jar": "pkg:maven/commons-vfs/commons-vfs@1.0",
|
||||
"/packages/cxf-rt-transports-http-2.7.3.jar": "pkg:maven/org.apache.cxf/cxf-rt-transports-http@2.7.3",
|
||||
"/packages/dubbo-3.1.4.jar:com.alibaba:hessian-lite": "pkg:maven/com.alibaba/hessian-lite@3.2.13",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-auth": "pkg:maven/org.apache.dubbo/dubbo-auth@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-cluster": "pkg:maven/org.apache.dubbo/dubbo-cluster@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-common": "pkg:maven/org.apache.dubbo/dubbo-common@3.1.4",
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
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
|
||||
@@ -1 +1 @@
|
||||
FROM anchore/test_images:java-1abc58f@sha256:3add9f90e9ed35739cc99b7830767e09eec921052e2412adf4491648c741f066
|
||||
FROM anchore/test_images:java-6ec7f71@sha256:e68db8ae97cc84b5b58f7bea0c138e00440aea188d74a2f4a2c2f6402e57d3a9
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -17,24 +17,24 @@ require (
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240312213626-055233e539b4
|
||||
github.com/anchore/stereoscope v0.0.3-0.20240501181043-2e9894674185
|
||||
github.com/anchore/stereoscope v0.0.2-0.20240229175558-fe426d1b1c84
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
||||
// we are hinting brotli to latest due to warning when installing archiver v3:
|
||||
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1
|
||||
github.com/charmbracelet/bubbles v0.18.0
|
||||
github.com/charmbracelet/bubbletea v0.26.2
|
||||
github.com/charmbracelet/bubbletea v0.25.0
|
||||
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.2+incompatible
|
||||
github.com/docker/docker v26.0.1+incompatible
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/elliotchance/phpserialize v1.4.0
|
||||
github.com/facebookincubator/nvdtools v0.1.5
|
||||
github.com/github/go-spdx/v2 v2.2.0
|
||||
github.com/gkampitakis/go-snaps v0.5.4
|
||||
github.com/gkampitakis/go-snaps v0.5.3
|
||||
github.com/go-git/go-billy/v5 v5.5.0
|
||||
github.com/go-git/go-git/v5 v5.12.0
|
||||
github.com/go-test/deep v1.1.0
|
||||
@@ -46,7 +46,7 @@ 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.0
|
||||
@@ -59,15 +59,14 @@ 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.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
|
||||
github.com/spdx/tools-golang v0.5.4
|
||||
github.com/spdx/tools-golang v0.5.3
|
||||
github.com/spf13/afero v1.11.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
@@ -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.9
|
||||
modernc.org/sqlite v1.29.7
|
||||
)
|
||||
|
||||
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,8 +101,9 @@ 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/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/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
|
||||
github.com/containerd/containerd v1.7.11 // indirect
|
||||
github.com/containerd/continuity v0.4.2 // indirect
|
||||
github.com/containerd/fifo v1.1.0 // indirect
|
||||
@@ -126,7 +122,6 @@ require (
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
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.6.0 // indirect
|
||||
@@ -151,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
|
||||
@@ -169,7 +165,7 @@ require (
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
@@ -207,7 +203,7 @@ 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
|
||||
@@ -222,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/sync v0.6.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
|
||||
|
||||
@@ -111,8 +111,8 @@ github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZV
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.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/anchore/stereoscope v0.0.2-0.20240229175558-fe426d1b1c84 h1:/E74wU51M87fX5UWHubLZiENXbuAci+xtbSb+JFsIYg=
|
||||
github.com/anchore/stereoscope v0.0.2-0.20240229175558-fe426d1b1c84/go.mod h1:evQiJMQG56Z7/L5uhA8kfhhjF6ESJUZzUH9ms6bQ2Co=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
@@ -155,8 +155,8 @@ 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.2 h1:Eeb+n75Om9gQ+I6YpbCXQRKHt5Pn4vMwusQpwLiEgJQ=
|
||||
github.com/charmbracelet/bubbletea v0.26.2/go.mod h1:6I0nZ3YHUrQj7YHIHlM8RySX4ZIthTliMY+W8X8b+Gs=
|
||||
github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
|
||||
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
|
||||
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.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
|
||||
@@ -168,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=
|
||||
@@ -182,6 +182,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||
github.com/containerd/containerd v1.7.11 h1:lfGKw3eU35sjV0aG2eYZTiwFEY1pCzxdzicHP3SZILw=
|
||||
github.com/containerd/containerd v1.7.11/go.mod h1:5UluHxHTX2rdvYuZ5OJTC5m/KJNs0Zs9wVoJm9zf5ZE=
|
||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||
@@ -221,8 +223,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.2+incompatible h1:UVX5ZOrrfTGZZYEP+ZDq3Xn9PdHNXaSYMFPDumMqG2k=
|
||||
github.com/docker/docker v26.1.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v26.0.1+incompatible h1:t39Hm6lpXuXtgkF0dm1t9a5HkbUfdGy6XbWexmGr+hA=
|
||||
github.com/docker/docker v26.0.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=
|
||||
@@ -255,8 +257,6 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.
|
||||
github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/facebookincubator/flog v0.0.0-20190930132826-d2511d0ce33c/go.mod h1:QGzNH9ujQ2ZUr/CjDGZGWeDAVStrWNjHeEcjJL96Nuk=
|
||||
github.com/facebookincubator/nvdtools v0.1.5 h1:jbmDT1nd6+k+rlvKhnkgMokrCAzHoASWE5LtHbX2qFQ=
|
||||
github.com/facebookincubator/nvdtools v0.1.5/go.mod h1:Kh55SAWnjckS96TBSrXI99KrEKH4iB0OJby3N8GRJO4=
|
||||
@@ -283,8 +283,8 @@ github.com/gkampitakis/ciinfo v0.3.0 h1:gWZlOC2+RYYttL0hBqcoQhM7h1qNkVqvRCV1fOvp
|
||||
github.com/gkampitakis/ciinfo v0.3.0/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
|
||||
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
|
||||
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
|
||||
github.com/gkampitakis/go-snaps v0.5.4 h1:GX+dkKmVsRenz7SoTbdIEL4KQARZctkMiZ8ZKprRwT8=
|
||||
github.com/gkampitakis/go-snaps v0.5.4/go.mod h1:ZABkO14uCuVxBHAXAfKG+bqNz+aa1bGPAg8jkI0Nk8Y=
|
||||
github.com/gkampitakis/go-snaps v0.5.3 h1:2cJnBgHzJhh0Jk5XBIyDYDe1Ylfncoa9r9bVJ5qvOAE=
|
||||
github.com/gkampitakis/go-snaps v0.5.3/go.mod h1:ZABkO14uCuVxBHAXAfKG+bqNz+aa1bGPAg8jkI0Nk8Y=
|
||||
github.com/glebarez/go-sqlite v1.20.3 h1:89BkqGOXR9oRmG58ZrzgoY/Fhy5x0M+/WV48U5zVrZ4=
|
||||
github.com/glebarez/go-sqlite v1.20.3/go.mod h1:u3N6D/wftiAzIOJtZl6BmedqxmmkDfH3q+ihjqxC9u0=
|
||||
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
|
||||
@@ -473,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=
|
||||
@@ -492,8 +492,8 @@ 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=
|
||||
@@ -544,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=
|
||||
@@ -588,8 +590,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 h1:kMlmsLSbjkikxQJ1IPwaM+7LJ9ltFu/fi8CRzvSnQmA=
|
||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
@@ -658,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=
|
||||
@@ -687,8 +687,8 @@ 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=
|
||||
@@ -714,8 +714,8 @@ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9yS
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
|
||||
github.com/spdx/tools-golang v0.5.4 h1:fRW4iz16P1ZCUtWStFqS6YiMgnK7WgfTFU/lrsYlvqY=
|
||||
github.com/spdx/tools-golang v0.5.4/go.mod h1:MVIsXx8ZZzaRWNQpUDhC4Dud34edUYJYecciXgrw5vE=
|
||||
github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQraY=
|
||||
github.com/spdx/tools-golang v0.5.3/go.mod h1:/ETOahiAo96Ob0/RAIBmFZw6XN0yTnyr/uFZm2NTMhI=
|
||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
@@ -777,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=
|
||||
@@ -867,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=
|
||||
@@ -958,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=
|
||||
@@ -990,8 +990,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1051,7 +1051,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -1072,15 +1071,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.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=
|
||||
@@ -1093,8 +1092,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=
|
||||
@@ -1370,8 +1369,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.9 h1:9RhNMklxJs+1596GNuAX+O/6040bvOwacTxuFcRuQow=
|
||||
modernc.org/sqlite v1.29.9/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA=
|
||||
modernc.org/sqlite v1.29.7 h1:Puwf5TIYuOipbcRnpFnLlGlR03DKenw8ggf3ijnuNQ0=
|
||||
modernc.org/sqlite v1.29.7/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=
|
||||
@@ -1379,4 +1378,4 @@ modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
||||
@@ -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.8"
|
||||
JSONSchemaVersion = "16.0.7"
|
||||
)
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
|
||||
"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 *relationshipIndex
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
relIndex = newRelationshipIndex(s.Relationships...)
|
||||
})
|
||||
|
||||
return generateRelationships(resolver, accessor, index, relIndex)
|
||||
}
|
||||
|
||||
func generateRelationships(resolver file.Resolver, accessor sbomsync.Accessor, index *sharedLibraryIndex, relIndex *relationshipIndex) []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 > ELF > Binary
|
||||
pkgsToDelete = append(pkgsToDelete, getBinaryPackagesToDelete(resolver, s)...)
|
||||
pkgsToDelete = append(pkgsToDelete, compareElfBinaryPackages(resolver, s)...)
|
||||
})
|
||||
return pkgsToDelete
|
||||
}
|
||||
|
||||
func compareElfBinaryPackages(resolver file.Resolver, s *sbom.SBOM) []artifact.ID {
|
||||
pkgsToDelete := make([]artifact.ID, 0)
|
||||
for _, p := range s.Artifacts.Packages.Sorted(pkg.BinaryPkg) {
|
||||
for _, loc := range p.Locations.ToSlice() {
|
||||
if loc.Annotations[pkg.EvidenceAnnotationKey] != pkg.PrimaryEvidenceAnnotation {
|
||||
continue
|
||||
}
|
||||
locations, err := resolver.FilesByPath(loc.RealPath)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Trace("unable to find path for owned file")
|
||||
continue
|
||||
}
|
||||
for _, ownedL := range locations {
|
||||
for _, pathPkg := range s.Artifacts.Packages.PackagesByPath(ownedL.RealPath) {
|
||||
// we only care about comparing binary packages to each other (not other types)
|
||||
if pathPkg.Type != pkg.BinaryPkg {
|
||||
continue
|
||||
}
|
||||
if _, ok := pathPkg.Metadata.(pkg.ELFBinaryPackageNoteJSONPayload); !ok {
|
||||
pkgsToDelete = append(pkgsToDelete, pathPkg.ID())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pkgsToDelete
|
||||
}
|
||||
|
||||
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 *relationshipIndex, 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,337 +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",
|
||||
Version: "",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation(glibcCoordinate.RealPath).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
Language: "",
|
||||
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",
|
||||
Version: "",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation(glibcCoordinate.RealPath).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation),
|
||||
),
|
||||
Language: "",
|
||||
Type: pkg.BinaryPkg,
|
||||
Metadata: pkg.BinarySignature{},
|
||||
}
|
||||
glibCBinaryClassifierPackage.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: newAccesor([]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: newAccesor([]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: newAccesor([]pkg.Package{glibCBinaryELFPackage, glibCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||
want: []artifact.ID{glibCBinaryClassifierPackage.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", "")
|
||||
parrallelLibCoordinate := 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(parrallelLibCoordinate.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{},
|
||||
want: make([]artifact.Relationship, 0),
|
||||
},
|
||||
{
|
||||
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,
|
||||
parrallelLibCoordinate.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,
|
||||
parrallelLibCoordinate: 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,
|
||||
parrallelLibCoordinate.RealPath,
|
||||
),
|
||||
coordinateIndex: map[file.Coordinates]file.Executable{
|
||||
glibcCoordinate: glibcExecutable,
|
||||
secondGlibcCoordinate: glibcExecutable,
|
||||
nestedLibCoordinate: syftTestFixtureExecutable,
|
||||
parrallelLibCoordinate: 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,
|
||||
parrallelLibCoordinate.RealPath,
|
||||
),
|
||||
coordinateIndex: map[file.Coordinates]file.Executable{
|
||||
glibcCoordinate: glibcExecutable,
|
||||
nestedLibCoordinate: syftTestFixtureExecutable,
|
||||
parrallelLibCoordinate: syftTestFixtureExecutable2,
|
||||
},
|
||||
packages: []pkg.Package{glibCPackage, glibCustomPackage, syftTestFixturePackage},
|
||||
prexistingRelationships: []artifact.Relationship{
|
||||
{
|
||||
From: glibCPackage,
|
||||
To: syftTestFixturePackage,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
},
|
||||
want: []artifact.Relationship{},
|
||||
},
|
||||
{
|
||||
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,
|
||||
parrallelLibCoordinate: syftTestFixtureExecutable2,
|
||||
},
|
||||
packages: []pkg.Package{glibCPackage, syftTestFixturePackage},
|
||||
want: []artifact.Relationship{},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
accessor := newAccesor(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 newAccesor(pkgs []pkg.Package, coordinateIndex map[file.Coordinates]file.Executable, prexistingRelationships []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 prexistingRelationships != nil {
|
||||
s.Relationships = prexistingRelationships
|
||||
}
|
||||
})
|
||||
return accessor
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
)
|
||||
|
||||
type relationshipIndex struct {
|
||||
typesByFromTo map[artifact.ID]map[artifact.ID]*strset.Set
|
||||
additional []artifact.Relationship
|
||||
}
|
||||
|
||||
func newRelationshipIndex(existing ...artifact.Relationship) *relationshipIndex {
|
||||
r := &relationshipIndex{
|
||||
typesByFromTo: make(map[artifact.ID]map[artifact.ID]*strset.Set),
|
||||
additional: make([]artifact.Relationship, 0),
|
||||
}
|
||||
for _, rel := range existing {
|
||||
r.track(rel)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// 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 *relationshipIndex) 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
|
||||
}
|
||||
|
||||
// add a new relationship to the index, returning true if the relationship is new to the index, false otherwise (thus is a duplicate).
|
||||
// nolint:unparam
|
||||
func (i *relationshipIndex) add(r artifact.Relationship) bool {
|
||||
if i.track(r) {
|
||||
i.additional = append(i.additional, r)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *relationshipIndex) newRelationships() []artifact.Relationship {
|
||||
return i.additional
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"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
|
||||
want *relationshipIndex
|
||||
}{
|
||||
{
|
||||
name: "newRelationshipIndex returns an empty index with no existing relationships",
|
||||
want: &relationshipIndex{
|
||||
typesByFromTo: make(map[artifact.ID]map[artifact.ID]*strset.Set),
|
||||
additional: make([]artifact.Relationship, 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "newRelationshipIndex returns an index which tracks existing relationships",
|
||||
given: []artifact.Relationship{
|
||||
{
|
||||
From: from,
|
||||
To: to,
|
||||
Type: artifact.EvidentByRelationship,
|
||||
},
|
||||
},
|
||||
want: &relationshipIndex{
|
||||
typesByFromTo: map[artifact.ID]map[artifact.ID]*strset.Set{
|
||||
"from": {
|
||||
"to": strset.New("evident-by"),
|
||||
},
|
||||
},
|
||||
additional: make([]artifact.Relationship, 0),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := newRelationshipIndex(tt.given...); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("newRelationshipIndex() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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 := newRelationshipIndex(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 := newRelationshipIndex(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)
|
||||
}
|
||||
@@ -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 := newAccesor(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 := newAccesor(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
|
||||
@@ -1,21 +1,15 @@
|
||||
package relationship
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
func Finalize(resolver file.Resolver, builder sbomsync.Builder, cfg cataloging.RelationshipsConfig, src artifact.Identifiable) {
|
||||
func Finalize(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 {
|
||||
byFileOwnershipOverlapWorker(accessor)
|
||||
@@ -27,12 +21,6 @@ func Finalize(resolver file.Resolver, builder sbomsync.Builder, cfg cataloging.R
|
||||
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) {
|
||||
@@ -45,6 +33,5 @@ func Finalize(resolver file.Resolver, builder sbomsync.Builder, cfg cataloging.R
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
evidentByRelationships = evidentBy(s.Artifacts.Packages)
|
||||
})
|
||||
|
||||
builder.AddRelationships(evidentByRelationships...)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -111,10 +111,10 @@ func NewPackageTask(cfg CatalogingFactoryConfig, c pkg.Cataloger, tags ...string
|
||||
if cfg.DataGenerationConfig.GenerateCPEs {
|
||||
// generate CPEs (note: this is excluded from package ID, so is safe to mutate)
|
||||
// we might have binary classified CPE already with the package so we want to append here
|
||||
dictionaryCPEs, ok := cpe.DictionaryFind(p)
|
||||
dictionaryCPE, ok := cpe.DictionaryFind(p)
|
||||
if ok {
|
||||
log.Tracef("used CPE dictionary to find CPEs for %s package %q: %s", p.Type, p.Name, dictionaryCPEs)
|
||||
p.CPEs = append(p.CPEs, dictionaryCPEs...)
|
||||
log.Tracef("used CPE dictionary to find CPE for %s package %q: %s", p.Type, p.Name, dictionaryCPE.Attributes.BindToFmtString())
|
||||
p.CPEs = append(p.CPEs, dictionaryCPE)
|
||||
} else {
|
||||
p.CPEs = append(p.CPEs, cpe.Generate(p)...)
|
||||
}
|
||||
|
||||
@@ -22,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 {
|
||||
fn := func(_ context.Context, _ file.Resolver, builder sbomsync.Builder) error {
|
||||
relationship.Finalize(
|
||||
resolver,
|
||||
builder,
|
||||
cfg,
|
||||
&sourceIdentifierAdapter{desc: src})
|
||||
|
||||
+2318
-3213
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.8/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",
|
||||
|
||||
+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 {
|
||||
|
||||
@@ -245,8 +245,6 @@ func toRootPackage(s source.Description) *spdx.Package {
|
||||
Supplier: helpers.NOASSERTION,
|
||||
},
|
||||
PackageDownloadLocation: helpers.NOASSERTION,
|
||||
PackageLicenseConcluded: helpers.NOASSERTION,
|
||||
PackageLicenseDeclared: helpers.NOASSERTION,
|
||||
}
|
||||
|
||||
if purl != nil {
|
||||
@@ -519,7 +517,9 @@ func toPackageOriginator(p pkg.Package) *spdx.Originator {
|
||||
}
|
||||
|
||||
func toPackageSupplier(p pkg.Package) *spdx.Supplier {
|
||||
kind, supplier := helpers.Supplier(p)
|
||||
// this uses the Originator function for now until
|
||||
// a better distinction can be made for supplier
|
||||
kind, supplier := helpers.Originator(p)
|
||||
if kind == "" || supplier == "" {
|
||||
return &spdx.Supplier{
|
||||
Supplier: helpers.NOASSERTION,
|
||||
@@ -624,9 +624,6 @@ func toFiles(s sbom.SBOM) (results []*spdx.File) {
|
||||
Checksums: toFileChecksums(digests),
|
||||
FileName: coordinates.RealPath,
|
||||
FileTypes: toFileTypes(metadata),
|
||||
LicenseInfoInFiles: []string{ // required in SPDX 2.2
|
||||
helpers.NOASSERTION,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
const (
|
||||
orgType = "Organization"
|
||||
personType = "Person"
|
||||
)
|
||||
|
||||
// Originator needs to conform to the SPDX spec here:
|
||||
// https://spdx.github.io/spdx-spec/v2.2.2/package-information/#76-package-originator-field
|
||||
//
|
||||
// Definition:
|
||||
//
|
||||
// If the package identified in the SPDX document originated from a different person or
|
||||
// organization than identified as Package Supplier (see 7.5 above), this field identifies from
|
||||
// where or whom the package originally came. In some cases, a package may be created and
|
||||
// originally distributed by a different third party than the Package Supplier of the package.
|
||||
// For example, the SPDX document identifies the package as glibc and the Package Supplier as
|
||||
// Red Hat, but the Free Software Foundation is the Package Originator.
|
||||
//
|
||||
// Use NOASSERTION if:
|
||||
//
|
||||
// - the SPDX document creator has attempted to but cannot reach a reasonable objective determination;
|
||||
// - the SPDX document creator has made no attempt to determine this field; or
|
||||
// - the SPDX document creator has intentionally provided no information (no meaning should be implied by doing so).
|
||||
//
|
||||
// Available options are: <omit>, NOASSERTION, Person: <person>, Organization: <org>
|
||||
// return values are: <type>, <value>
|
||||
func Originator(p pkg.Package) (typ string, author string) { // nolint: funlen
|
||||
if !hasMetadata(p) {
|
||||
return typ, author
|
||||
}
|
||||
|
||||
switch metadata := p.Metadata.(type) {
|
||||
case pkg.ApkDBEntry:
|
||||
author = metadata.Maintainer
|
||||
|
||||
case pkg.DotnetPortableExecutableEntry:
|
||||
typ = orgType
|
||||
author = metadata.CompanyName
|
||||
|
||||
case pkg.DpkgDBEntry:
|
||||
author = metadata.Maintainer
|
||||
|
||||
case pkg.JavaArchive:
|
||||
if metadata.Manifest != nil {
|
||||
author = metadata.Manifest.Main.MustGet("Specification-Vendor")
|
||||
if author == "" {
|
||||
author = metadata.Manifest.Main.MustGet("Implementation-Vendor")
|
||||
}
|
||||
}
|
||||
|
||||
case pkg.LinuxKernelModule:
|
||||
author = metadata.Author
|
||||
|
||||
case pkg.PhpComposerLockEntry:
|
||||
if len(metadata.Authors) > 0 {
|
||||
entry := metadata.Authors[0]
|
||||
author = formatPersonOrOrg(entry.Name, entry.Email)
|
||||
}
|
||||
|
||||
case pkg.PhpComposerInstalledEntry:
|
||||
if len(metadata.Authors) > 0 {
|
||||
entry := metadata.Authors[0]
|
||||
author = formatPersonOrOrg(entry.Name, entry.Email)
|
||||
}
|
||||
|
||||
case pkg.RDescription:
|
||||
// this is most likely to have a name and email
|
||||
author = metadata.Maintainer
|
||||
|
||||
if author == "" {
|
||||
author = metadata.Author
|
||||
}
|
||||
|
||||
case pkg.NpmPackage:
|
||||
author = metadata.Author
|
||||
|
||||
case pkg.PythonPackage:
|
||||
author = formatPersonOrOrg(metadata.Author, metadata.AuthorEmail)
|
||||
|
||||
case pkg.RubyGemspec:
|
||||
if len(metadata.Authors) > 0 {
|
||||
author = metadata.Authors[0]
|
||||
}
|
||||
case pkg.RpmDBEntry:
|
||||
typ = orgType
|
||||
author = metadata.Vendor
|
||||
|
||||
case pkg.RpmArchive:
|
||||
typ = orgType
|
||||
author = metadata.Vendor
|
||||
|
||||
case pkg.WordpressPluginEntry:
|
||||
// it seems that the vast majority of the time the author is an org, not a person
|
||||
typ = orgType
|
||||
author = metadata.Author
|
||||
}
|
||||
|
||||
if typ == "" && author != "" {
|
||||
typ = personType
|
||||
}
|
||||
|
||||
return typ, parseAndFormatPersonOrOrg(author)
|
||||
}
|
||||
|
||||
// Supplier needs to conform to the SPDX spec here:
|
||||
// https://spdx.github.io/spdx-spec/v2.2.2/package-information/#75-package-supplier-field
|
||||
//
|
||||
// Definition:
|
||||
//
|
||||
// Identify the actual distribution source for the package/directory identified in the SPDX document. This might
|
||||
// or might not be different from the originating distribution source for the package. The name of the Package Supplier
|
||||
// shall be an organization or recognized author and not a web site. For example, SourceForge is a host website, not a
|
||||
// supplier, the supplier for https://sourceforge.net/projects/bridge/ is “The Linux Foundation.”
|
||||
//
|
||||
// Use NOASSERTION if:
|
||||
//
|
||||
// - the SPDX document creator has attempted to but cannot reach a reasonable objective determination;
|
||||
// - the SPDX document creator has made no attempt to determine this field; or
|
||||
// - the SPDX document creator has intentionally provided no information (no meaning should be implied by doing so).
|
||||
//
|
||||
// Available options are: <omit>, NOASSERTION, Person: <person>, Organization: <org>
|
||||
// return values are: <type>, <value>
|
||||
func Supplier(p pkg.Package) (typ string, author string) {
|
||||
if !hasMetadata(p) {
|
||||
return
|
||||
}
|
||||
|
||||
if metadata, ok := p.Metadata.(pkg.AlpmDBEntry); ok {
|
||||
// most indications here are that this is the person that is simply packaging the upstream software. Most
|
||||
// of the time this is not the original author of the upstream software (which would be the originator).
|
||||
// Though it is possible for users to be both the packager and the author, this code cannot distinct this
|
||||
// case and sticks to the semantically correct interpretation of the "packager" (which says nothing about the
|
||||
// authorship of the upstream software).
|
||||
author = metadata.Packager
|
||||
}
|
||||
|
||||
if author == "" {
|
||||
// TODO: this uses the Originator function for now until a better distinction can be made for supplier
|
||||
return Originator(p)
|
||||
}
|
||||
|
||||
if typ == "" && author != "" {
|
||||
typ = personType
|
||||
}
|
||||
|
||||
return typ, parseAndFormatPersonOrOrg(author)
|
||||
}
|
||||
|
||||
var nameEmailURLPattern = regexp.MustCompile(`^(?P<name>[^<>()]*)( <(?P<email>[^@]+@\w+\.\w+)>)?( \((?P<url>.*)\))?$`)
|
||||
|
||||
func parseAndFormatPersonOrOrg(s string) string {
|
||||
name, email, _ := parseNameEmailURL(s)
|
||||
return formatPersonOrOrg(name, email)
|
||||
}
|
||||
|
||||
func parseNameEmailURL(s string) (name, email, url string) {
|
||||
fields := internal.MatchNamedCaptureGroups(nameEmailURLPattern, s)
|
||||
name = strings.TrimSpace(fields["name"])
|
||||
email = strings.TrimSpace(fields["email"])
|
||||
url = strings.TrimSpace(fields["url"])
|
||||
|
||||
if email == "" {
|
||||
if approximatesAsEmail(url) {
|
||||
email = url
|
||||
url = ""
|
||||
} else if approximatesAsEmail(name) {
|
||||
email = name
|
||||
name = ""
|
||||
}
|
||||
}
|
||||
return name, email, url
|
||||
}
|
||||
|
||||
func approximatesAsEmail(s string) bool {
|
||||
atIndex := strings.Index(s, "@")
|
||||
if atIndex == -1 {
|
||||
return false
|
||||
}
|
||||
dotIndex := strings.Index(s[atIndex:], ".")
|
||||
return dotIndex != -1
|
||||
}
|
||||
|
||||
func formatPersonOrOrg(name, email string) string {
|
||||
name = strings.TrimSpace(name)
|
||||
email = strings.TrimSpace(email)
|
||||
|
||||
blankName := name == ""
|
||||
blankEmail := email == ""
|
||||
|
||||
if !blankEmail && !blankName {
|
||||
return fmt.Sprintf("%s (%s)", name, email)
|
||||
}
|
||||
if !blankName && blankEmail {
|
||||
return name
|
||||
}
|
||||
if blankName && !blankEmail {
|
||||
return email
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1,482 +0,0 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/internal/packagemetadata"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func Test_OriginatorSupplier(t *testing.T) {
|
||||
completionTester := packagemetadata.NewCompletionTester(t,
|
||||
pkg.BinarySignature{},
|
||||
pkg.CocoaPodfileLockEntry{},
|
||||
pkg.ConanV1LockEntry{},
|
||||
pkg.ConanV2LockEntry{}, // the field Username might be the username of either the package originator or the supplier (unclear currently)
|
||||
pkg.ConanfileEntry{},
|
||||
pkg.ConaninfoEntry{},
|
||||
pkg.DartPubspecLockEntry{},
|
||||
pkg.DotnetDepsEntry{},
|
||||
pkg.ELFBinaryPackageNoteJSONPayload{},
|
||||
pkg.ElixirMixLockEntry{},
|
||||
pkg.ErlangRebarLockEntry{},
|
||||
pkg.GolangBinaryBuildinfoEntry{},
|
||||
pkg.GolangModuleEntry{},
|
||||
pkg.HackageStackYamlLockEntry{},
|
||||
pkg.HackageStackYamlEntry{},
|
||||
pkg.LinuxKernel{},
|
||||
pkg.MicrosoftKbPatch{},
|
||||
pkg.NixStoreEntry{},
|
||||
pkg.NpmPackageLockEntry{},
|
||||
pkg.PhpComposerInstalledEntry{},
|
||||
pkg.PhpPeclEntry{},
|
||||
pkg.PortageEntry{},
|
||||
pkg.PythonPipfileLockEntry{},
|
||||
pkg.PythonRequirementsEntry{},
|
||||
pkg.PythonPoetryLockEntry{},
|
||||
pkg.RustBinaryAuditEntry{},
|
||||
pkg.RustCargoLockEntry{},
|
||||
pkg.SwiftPackageManagerResolvedEntry{},
|
||||
pkg.YarnLockEntry{},
|
||||
)
|
||||
tests := []struct {
|
||||
name string
|
||||
input pkg.Package
|
||||
originator string
|
||||
supplier string
|
||||
}{
|
||||
{
|
||||
// note: since this is an optional field, no value is preferred over NONE or NOASSERTION
|
||||
name: "no metadata",
|
||||
input: pkg.Package{},
|
||||
originator: "",
|
||||
supplier: "",
|
||||
},
|
||||
{
|
||||
// note: since this is an optional field, no value is preferred over NONE or NOASSERTION
|
||||
name: "empty author on existing metadata",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.NpmPackage{
|
||||
Author: "",
|
||||
},
|
||||
},
|
||||
originator: "",
|
||||
supplier: "",
|
||||
},
|
||||
{
|
||||
name: "from apk",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Maintainer: "auth",
|
||||
},
|
||||
},
|
||||
originator: "Person: auth",
|
||||
supplier: "Person: auth",
|
||||
},
|
||||
{
|
||||
name: "from alpm",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Packager: "someone",
|
||||
},
|
||||
},
|
||||
originator: "",
|
||||
supplier: "Person: someone",
|
||||
},
|
||||
{
|
||||
name: "from dotnet -- PE binary",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.DotnetPortableExecutableEntry{
|
||||
CompanyName: "Microsoft Corporation",
|
||||
},
|
||||
},
|
||||
originator: "Organization: Microsoft Corporation",
|
||||
supplier: "Organization: Microsoft Corporation",
|
||||
},
|
||||
{
|
||||
name: "from dpkg",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Maintainer: "auth",
|
||||
},
|
||||
},
|
||||
originator: "Person: auth",
|
||||
supplier: "Person: auth",
|
||||
},
|
||||
{
|
||||
name: "from gem",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.RubyGemspec{
|
||||
Authors: []string{
|
||||
"auth1",
|
||||
"auth2",
|
||||
},
|
||||
},
|
||||
},
|
||||
originator: "Person: auth1",
|
||||
supplier: "Person: auth1",
|
||||
},
|
||||
{
|
||||
name: "from java -- spec > impl cendor in main manifest section",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: pkg.KeyValues{
|
||||
{
|
||||
Key: "Implementation-Vendor",
|
||||
Value: "auth-impl",
|
||||
},
|
||||
{
|
||||
Key: "Specification-Vendor",
|
||||
Value: "auth-spec",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
originator: "Person: auth-spec",
|
||||
supplier: "Person: auth-spec",
|
||||
},
|
||||
{
|
||||
name: "from java -- fallback to impl vendor in main manifest section",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Main: pkg.KeyValues{
|
||||
{
|
||||
Key: "Implementation-Vendor",
|
||||
Value: "auth-impl",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
originator: "Person: auth-impl",
|
||||
supplier: "Person: auth-impl",
|
||||
},
|
||||
{
|
||||
name: "from java -- non-main manifest sections ignored",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
Manifest: &pkg.JavaManifest{
|
||||
Sections: []pkg.KeyValues{
|
||||
{
|
||||
{
|
||||
Key: "Implementation-Vendor",
|
||||
Value: "auth-impl",
|
||||
},
|
||||
},
|
||||
},
|
||||
Main: pkg.KeyValues{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// note: empty!
|
||||
},
|
||||
{
|
||||
name: "from linux kernel module",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.LinuxKernelModule{
|
||||
Author: "auth",
|
||||
},
|
||||
},
|
||||
originator: "Person: auth",
|
||||
supplier: "Person: auth",
|
||||
},
|
||||
{
|
||||
name: "from npm",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.NpmPackage{
|
||||
Author: "auth",
|
||||
},
|
||||
},
|
||||
originator: "Person: auth",
|
||||
supplier: "Person: auth",
|
||||
},
|
||||
{
|
||||
name: "from npm -- name, email, and url",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.NpmPackage{
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
},
|
||||
},
|
||||
originator: "Person: Isaac Z. Schlueter (i@izs.me)",
|
||||
supplier: "Person: Isaac Z. Schlueter (i@izs.me)",
|
||||
},
|
||||
{
|
||||
name: "from npm -- name, email",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.NpmPackage{
|
||||
Author: "Isaac Z. Schlueter <i@izs.me>",
|
||||
},
|
||||
},
|
||||
originator: "Person: Isaac Z. Schlueter (i@izs.me)",
|
||||
supplier: "Person: Isaac Z. Schlueter (i@izs.me)",
|
||||
},
|
||||
{
|
||||
name: "from php composer installed file",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.PhpComposerInstalledEntry{
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "auth",
|
||||
Email: "me@auth.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
originator: "Person: auth (me@auth.com)",
|
||||
supplier: "Person: auth (me@auth.com)",
|
||||
},
|
||||
{
|
||||
name: "from php composer installed file",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.PhpComposerLockEntry{
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "auth",
|
||||
Email: "me@auth.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
originator: "Person: auth (me@auth.com)",
|
||||
supplier: "Person: auth (me@auth.com)",
|
||||
},
|
||||
{
|
||||
name: "from python - just name",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.PythonPackage{
|
||||
Author: "auth",
|
||||
},
|
||||
},
|
||||
originator: "Person: auth",
|
||||
supplier: "Person: auth",
|
||||
},
|
||||
{
|
||||
name: "from python - just email",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.PythonPackage{
|
||||
AuthorEmail: "auth@auth.gov",
|
||||
},
|
||||
},
|
||||
originator: "Person: auth@auth.gov",
|
||||
supplier: "Person: auth@auth.gov",
|
||||
},
|
||||
{
|
||||
name: "from python - both name and email",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.PythonPackage{
|
||||
Author: "auth",
|
||||
AuthorEmail: "auth@auth.gov",
|
||||
},
|
||||
},
|
||||
originator: "Person: auth (auth@auth.gov)",
|
||||
supplier: "Person: auth (auth@auth.gov)",
|
||||
},
|
||||
{
|
||||
name: "from r -- maintainer > author",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.RDescription{
|
||||
Author: "author",
|
||||
Maintainer: "maintainer",
|
||||
},
|
||||
},
|
||||
originator: "Person: maintainer",
|
||||
supplier: "Person: maintainer",
|
||||
},
|
||||
{
|
||||
name: "from r -- fallback to author",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.RDescription{
|
||||
Author: "author",
|
||||
},
|
||||
},
|
||||
originator: "Person: author",
|
||||
supplier: "Person: author",
|
||||
},
|
||||
{
|
||||
name: "from rpm archive",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.RpmArchive{
|
||||
Vendor: "auth",
|
||||
},
|
||||
},
|
||||
originator: "Organization: auth",
|
||||
supplier: "Organization: auth",
|
||||
},
|
||||
{
|
||||
name: "from rpm DB",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Vendor: "auth",
|
||||
},
|
||||
},
|
||||
originator: "Organization: auth",
|
||||
supplier: "Organization: auth",
|
||||
},
|
||||
{
|
||||
name: "from wordpress plugin",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.WordpressPluginEntry{
|
||||
Author: "auth",
|
||||
},
|
||||
},
|
||||
originator: "Organization: auth",
|
||||
supplier: "Organization: auth",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
completionTester.Tested(t, test.input.Metadata)
|
||||
|
||||
typ, value := Originator(test.input)
|
||||
if typ != "" {
|
||||
value = typ + ": " + value
|
||||
}
|
||||
assert.Equal(t, test.originator, value)
|
||||
|
||||
typ, value = Supplier(test.input)
|
||||
if typ != "" {
|
||||
value = typ + ": " + value
|
||||
}
|
||||
assert.Equal(t, test.supplier, value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseNameEmailUrl(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantName string
|
||||
wantEmail string
|
||||
wantUrl string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
input: "",
|
||||
},
|
||||
{
|
||||
name: "npm-like: name only",
|
||||
input: "Isaac Z. Schlueter",
|
||||
wantName: "Isaac Z. Schlueter",
|
||||
},
|
||||
{
|
||||
name: "npm-like: name and email",
|
||||
input: "Ray Nos <bogus2@gmail.com>",
|
||||
wantName: "Ray Nos",
|
||||
wantEmail: "bogus2@gmail.com",
|
||||
},
|
||||
{
|
||||
name: "npm-like: name and url",
|
||||
input: "Ray Nos (http://example.com)",
|
||||
wantName: "Ray Nos",
|
||||
wantUrl: "http://example.com",
|
||||
},
|
||||
{
|
||||
name: "npm-like: name, email, and url",
|
||||
input: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
wantName: "Isaac Z. Schlueter",
|
||||
wantEmail: "i@izs.me",
|
||||
wantUrl: "http://blog.izs.me",
|
||||
},
|
||||
{
|
||||
name: "mixed input: email only",
|
||||
input: "i@izs.me",
|
||||
wantEmail: "i@izs.me",
|
||||
},
|
||||
{
|
||||
name: "mixed input: email in url",
|
||||
input: "my name (i@izs.me)",
|
||||
wantName: "my name",
|
||||
wantEmail: "i@izs.me",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotName, gotEmail, gotUrl := parseNameEmailURL(tt.input)
|
||||
assert.Equal(t, tt.wantName, gotName)
|
||||
assert.Equal(t, tt.wantEmail, gotEmail)
|
||||
assert.Equal(t, tt.wantUrl, gotUrl)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_formatPersonOrOrg(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
email string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "name only",
|
||||
input: "Isaac Z. Schlueter",
|
||||
want: "Isaac Z. Schlueter",
|
||||
},
|
||||
{
|
||||
name: "email only",
|
||||
email: "i@something.com",
|
||||
want: "i@something.com",
|
||||
},
|
||||
{
|
||||
name: "name and email",
|
||||
input: "Isaac Z. Schlueter",
|
||||
email: "i@something.com",
|
||||
want: "Isaac Z. Schlueter (i@something.com)",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, formatPersonOrOrg(tt.input, tt.email))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_approximatesAsEmail(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
input: "",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "no at",
|
||||
input: "something.com",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "no dot",
|
||||
input: "something@com",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "dot before at",
|
||||
input: "something.com@nothing",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
input: "something@nothing.com",
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, approximatesAsEmail(tt.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func Test_Originator(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input pkg.Package
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
// note: since this is an optional field, no value is preferred over NONE or NOASSERTION
|
||||
name: "no metadata",
|
||||
input: pkg.Package{},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "from gem",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.RubyGemspec{
|
||||
Authors: []string{
|
||||
"auth1",
|
||||
"auth2",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "Person: auth1",
|
||||
},
|
||||
{
|
||||
name: "from npm",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.NpmPackage{
|
||||
Author: "auth",
|
||||
},
|
||||
},
|
||||
expected: "Person: auth",
|
||||
},
|
||||
{
|
||||
name: "from apk",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Maintainer: "auth",
|
||||
},
|
||||
},
|
||||
expected: "Person: auth",
|
||||
},
|
||||
{
|
||||
name: "from python - just name",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.PythonPackage{
|
||||
Author: "auth",
|
||||
},
|
||||
},
|
||||
expected: "Person: auth",
|
||||
},
|
||||
{
|
||||
name: "from python - just email",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.PythonPackage{
|
||||
AuthorEmail: "auth@auth.gov",
|
||||
},
|
||||
},
|
||||
expected: "Person: auth@auth.gov",
|
||||
},
|
||||
{
|
||||
name: "from python - both name and email",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.PythonPackage{
|
||||
Author: "auth",
|
||||
AuthorEmail: "auth@auth.gov",
|
||||
},
|
||||
},
|
||||
expected: "Person: auth (auth@auth.gov)",
|
||||
},
|
||||
{
|
||||
name: "from rpm",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Vendor: "auth",
|
||||
},
|
||||
},
|
||||
expected: "Organization: auth",
|
||||
},
|
||||
{
|
||||
name: "from dpkg",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Maintainer: "auth",
|
||||
},
|
||||
},
|
||||
expected: "Person: auth",
|
||||
},
|
||||
{
|
||||
// note: since this is an optional field, no value is preferred over NONE or NOASSERTION
|
||||
name: "empty",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.NpmPackage{
|
||||
Author: "",
|
||||
},
|
||||
},
|
||||
expected: "",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
typ, value := Originator(test.input)
|
||||
if typ != "" {
|
||||
value = typ + ": " + value
|
||||
}
|
||||
assert.Equal(t, test.expected, value)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
// Originator needs to conform to the SPDX spec here:
|
||||
// https://spdx.github.io/spdx-spec/package-information/#76-package-originator-field
|
||||
// Available options are: <omit>, NOASSERTION, Person: <person>, Organization: <org>
|
||||
// return values are: <type>, <value>
|
||||
func Originator(p pkg.Package) (string, string) {
|
||||
typ := ""
|
||||
author := ""
|
||||
if hasMetadata(p) {
|
||||
switch metadata := p.Metadata.(type) {
|
||||
case pkg.ApkDBEntry:
|
||||
author = metadata.Maintainer
|
||||
case pkg.NpmPackage:
|
||||
author = metadata.Author
|
||||
case pkg.PythonPackage:
|
||||
author = metadata.Author
|
||||
if author == "" {
|
||||
author = metadata.AuthorEmail
|
||||
} else if metadata.AuthorEmail != "" {
|
||||
author = fmt.Sprintf("%s (%s)", author, metadata.AuthorEmail)
|
||||
}
|
||||
case pkg.RubyGemspec:
|
||||
if len(metadata.Authors) > 0 {
|
||||
author = metadata.Authors[0]
|
||||
}
|
||||
case pkg.RpmDBEntry:
|
||||
typ = "Organization"
|
||||
author = metadata.Vendor
|
||||
case pkg.DpkgDBEntry:
|
||||
author = metadata.Maintainer
|
||||
}
|
||||
if typ == "" && author != "" {
|
||||
typ = "Person"
|
||||
}
|
||||
}
|
||||
return typ, author
|
||||
}
|
||||
@@ -9,8 +9,6 @@ import (
|
||||
"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"
|
||||
@@ -115,74 +113,6 @@ func TestSPDXJSONImageEncoder(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
func TestSPDX22JSONRequredProperties(t *testing.T) {
|
||||
cfg := DefaultEncoderConfig()
|
||||
cfg.Pretty = true
|
||||
cfg.Version = "2.2"
|
||||
|
||||
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
coords := file.Coordinates{
|
||||
RealPath: "/some/file",
|
||||
FileSystemID: "ac897d978b6c38749a1",
|
||||
}
|
||||
|
||||
p1 := pkg.Package{
|
||||
Name: "files-analyzed-true",
|
||||
Version: "v1",
|
||||
Locations: file.NewLocationSet(file.NewLocation(coords.RealPath)),
|
||||
Licenses: pkg.LicenseSet{},
|
||||
Language: pkg.Java,
|
||||
Metadata: pkg.JavaArchive{
|
||||
ArchiveDigests: []file.Digest{
|
||||
{
|
||||
Algorithm: "sha256",
|
||||
Value: "a9b87321a9879c79d87987987a97c97b9789ce978dffea987",
|
||||
},
|
||||
},
|
||||
Parent: nil,
|
||||
},
|
||||
}
|
||||
p1.SetID()
|
||||
|
||||
p2 := pkg.Package{
|
||||
Name: "files-analyzed-false",
|
||||
Version: "v2",
|
||||
}
|
||||
p2.SetID()
|
||||
|
||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||
testutil.EncoderSnapshotTestConfig{
|
||||
Subject: sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
Packages: pkg.NewCollection(p1, p2),
|
||||
FileDigests: map[file.Coordinates][]file.Digest{
|
||||
coords: {
|
||||
{
|
||||
Algorithm: "sha1",
|
||||
Value: "3b4ab96c371d913e2a88c269844b6c5fb5cbe761",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Relationships: []artifact.Relationship{
|
||||
{
|
||||
From: p1,
|
||||
To: coords,
|
||||
Type: artifact.ContainsRelationship,
|
||||
},
|
||||
},
|
||||
},
|
||||
Format: enc,
|
||||
UpdateSnapshot: *updateSnapshot,
|
||||
PersistRedactionsInSnapshot: true,
|
||||
IsJSON: true,
|
||||
Redactor: redactor(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestSPDXRelationshipOrder(t *testing.T) {
|
||||
testImage := "image-simple"
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-2.2",
|
||||
"dataLicense": "CC0-1.0",
|
||||
"SPDXID": "SPDXRef-DOCUMENT",
|
||||
"name": "unknown",
|
||||
"documentNamespace":"redacted",
|
||||
"creationInfo": {
|
||||
"licenseListVersion":"redacted",
|
||||
"creators": [
|
||||
"Organization: Anchore, Inc",
|
||||
"Tool: -"
|
||||
],
|
||||
"created":"redacted"
|
||||
},
|
||||
"packages": [
|
||||
{
|
||||
"SPDXID": "SPDXRef-Package-files-analyzed-false-7d37ba9d2f7c574b",
|
||||
"copyrightText": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": false,
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"name": "files-analyzed-false",
|
||||
"sourceInfo": "acquired package info from the following paths: ",
|
||||
"supplier": "NOASSERTION",
|
||||
"versionInfo": "v2"
|
||||
},
|
||||
{
|
||||
"name": "files-analyzed-true",
|
||||
"SPDXID": "SPDXRef-Package-files-analyzed-true-035066c2086b8bb4",
|
||||
"versionInfo": "v1",
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": true,
|
||||
"packageVerificationCode": {
|
||||
"packageVerificationCodeValue": "6fe0c471faaaa544e33cae0918eabcdc1c798d18"
|
||||
},
|
||||
"checksums": [
|
||||
{
|
||||
"algorithm": "SHA256",
|
||||
"checksumValue": "a9b87321a9879c79d87987987a97c97b9789ce978dffea987"
|
||||
}
|
||||
],
|
||||
"sourceInfo": "acquired package info from the following paths: /some/file",
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"copyrightText": "NOASSERTION"
|
||||
},
|
||||
{
|
||||
"SPDXID": "SPDXRef-DocumentRoot-Unknown-",
|
||||
"copyrightText": "",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": false,
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"name": "",
|
||||
"supplier": "NOASSERTION"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"fileName": "/some/file",
|
||||
"SPDXID": "SPDXRef-File-some-file-2c5bc344430decac",
|
||||
"checksums": [
|
||||
{
|
||||
"algorithm": "SHA1",
|
||||
"checksumValue": "3b4ab96c371d913e2a88c269844b6c5fb5cbe761"
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": "",
|
||||
"comment": "layerID: ac897d978b6c38749a1"
|
||||
}
|
||||
],
|
||||
"relationships": [
|
||||
{
|
||||
"spdxElementId": "SPDXRef-Package-files-analyzed-true-035066c2086b8bb4",
|
||||
"relatedSpdxElement": "SPDXRef-File-some-file-2c5bc344430decac",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DocumentRoot-Unknown-",
|
||||
"relatedSpdxElement": "SPDXRef-Package-files-analyzed-false-7d37ba9d2f7c574b",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DocumentRoot-Unknown-",
|
||||
"relatedSpdxElement": "SPDXRef-Package-files-analyzed-true-035066c2086b8bb4",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DOCUMENT",
|
||||
"relatedSpdxElement": "SPDXRef-DocumentRoot-Unknown-",
|
||||
"relationshipType": "DESCRIBES"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -67,8 +67,6 @@
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": false,
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"primaryPackagePurpose": "FILE"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -74,8 +74,6 @@
|
||||
"checksumValue": "2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceCategory": "PACKAGE-MANAGER",
|
||||
|
||||
@@ -74,8 +74,6 @@
|
||||
"checksumValue": "2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceCategory": "PACKAGE-MANAGER",
|
||||
@@ -100,9 +98,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -118,9 +113,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -136,9 +128,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -154,9 +143,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -172,9 +158,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -190,9 +173,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
}
|
||||
],
|
||||
|
||||
@@ -16,8 +16,6 @@ PackageSupplier: NOASSERTION
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
PrimaryPackagePurpose: FILE
|
||||
FilesAnalyzed: false
|
||||
PackageLicenseConcluded: NOASSERTION
|
||||
PackageLicenseDeclared: NOASSERTION
|
||||
|
||||
##### Package: @at-sign
|
||||
|
||||
|
||||
@@ -15,42 +15,36 @@ SPDXID: SPDXRef-File-a1-f6-9c2f7510199b17f6
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /d1/f3
|
||||
SPDXID: SPDXRef-File-d1-f3-c6f5b29dca12661f
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /d2/f4
|
||||
SPDXID: SPDXRef-File-d2-f4-c641caa71518099f
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /f1
|
||||
SPDXID: SPDXRef-File-f1-5265a4dde3edbf7c
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /f2
|
||||
SPDXID: SPDXRef-File-f2-f9e49132a4b96ccd
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /z1/f5
|
||||
SPDXID: SPDXRef-File-z1-f5-839d99ee67d9d174
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
##### Package: user-image-input
|
||||
|
||||
@@ -62,8 +56,6 @@ PackageDownloadLocation: NOASSERTION
|
||||
PrimaryPackagePurpose: CONTAINER
|
||||
FilesAnalyzed: false
|
||||
PackageChecksum: SHA256: 2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368
|
||||
PackageLicenseConcluded: NOASSERTION
|
||||
PackageLicenseDeclared: NOASSERTION
|
||||
ExternalRef: PACKAGE-MANAGER purl pkg:oci/user-image-input@sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368?arch=
|
||||
|
||||
##### Package: package-2
|
||||
|
||||
-2
@@ -16,8 +16,6 @@ PackageSupplier: NOASSERTION
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
PrimaryPackagePurpose: FILE
|
||||
FilesAnalyzed: false
|
||||
PackageLicenseConcluded: NOASSERTION
|
||||
PackageLicenseDeclared: NOASSERTION
|
||||
|
||||
##### Package: package-2
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ PackageDownloadLocation: NOASSERTION
|
||||
PrimaryPackagePurpose: CONTAINER
|
||||
FilesAnalyzed: false
|
||||
PackageChecksum: SHA256: 2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368
|
||||
PackageLicenseConcluded: NOASSERTION
|
||||
PackageLicenseDeclared: NOASSERTION
|
||||
ExternalRef: PACKAGE-MANAGER purl pkg:oci/user-image-input@sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368?arch=
|
||||
|
||||
##### Package: package-2
|
||||
|
||||
+40
-8
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
@@ -22,16 +21,21 @@ func GetSource(ctx context.Context, userInput string, cfg *GetSourceConfig) (sou
|
||||
}
|
||||
|
||||
var errs []error
|
||||
var fileNotFoundProviders []string
|
||||
var fileNotfound error
|
||||
|
||||
// call each source provider until we find a valid source
|
||||
for _, p := range providers {
|
||||
src, err := p.Provide(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
fileNotFoundProviders = append(fileNotFoundProviders, p.Name())
|
||||
} else {
|
||||
errs = append(errs, fmt.Errorf("%s: %w", p.Name(), err))
|
||||
err = eachError(err, func(err error) error {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
fileNotfound = err
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if src != nil {
|
||||
@@ -48,8 +52,8 @@ func GetSource(ctx context.Context, userInput string, cfg *GetSourceConfig) (sou
|
||||
}
|
||||
}
|
||||
|
||||
if len(fileNotFoundProviders) > 0 {
|
||||
errs = append(errs, fmt.Errorf("additionally, the following providers failed with %w: %s", os.ErrNotExist, strings.Join(fileNotFoundProviders, ", ")))
|
||||
if fileNotfound != nil {
|
||||
errs = append([]error{fileNotfound}, errs...)
|
||||
}
|
||||
return nil, sourceError(userInput, errs...)
|
||||
}
|
||||
@@ -67,3 +71,31 @@ func sourceError(userInput string, errs ...error) error {
|
||||
}
|
||||
return fmt.Errorf("errors occurred attempting to resolve '%s':%s", userInput, errorTexts)
|
||||
}
|
||||
|
||||
func eachError(err error, fn func(error) error) error {
|
||||
out := fn(err)
|
||||
// unwrap singly wrapped errors
|
||||
if e, ok := err.(interface {
|
||||
Unwrap() error
|
||||
}); ok {
|
||||
wrapped := e.Unwrap()
|
||||
got := eachError(wrapped, fn)
|
||||
// return the outer error if received the same wrapped error
|
||||
if errors.Is(got, wrapped) {
|
||||
return err
|
||||
}
|
||||
return got
|
||||
}
|
||||
// unwrap errors from errors.Join
|
||||
if errs, ok := err.(interface {
|
||||
Unwrap() []error
|
||||
}); ok {
|
||||
for _, e := range errs.Unwrap() {
|
||||
e = eachError(e, fn)
|
||||
if e != nil {
|
||||
out = errors.Join(out, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
macho "github.com/anchore/go-macholibre"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
|
||||
// UnionReader is a single interface with all reading functions needed by multi-arch binary catalogers
|
||||
@@ -45,17 +44,6 @@ func GetUnionReader(readerCloser io.ReadCloser) (UnionReader, error) {
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
// file.LocationReadCloser embeds a ReadCloser, which is likely
|
||||
// to implement UnionReader. Check whether the embedded read closer
|
||||
// implements UnionReader, and just return that if so.
|
||||
r, ok := readerCloser.(file.LocationReadCloser)
|
||||
if ok {
|
||||
ur, ok := r.ReadCloser.(UnionReader)
|
||||
if ok {
|
||||
return ur, nil
|
||||
}
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(readerCloser)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read contents from binary: %w", err)
|
||||
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
|
||||
func Test_getUnionReader_notUnionReader(t *testing.T) {
|
||||
@@ -30,34 +28,3 @@ func Test_getUnionReader_notUnionReader(t *testing.T) {
|
||||
|
||||
assert.Equal(t, expectedContents, string(b))
|
||||
}
|
||||
|
||||
type panickingUnionReader struct{}
|
||||
|
||||
func (p2 *panickingUnionReader) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
panic("don't call this in your unit test!")
|
||||
}
|
||||
|
||||
func (p2 *panickingUnionReader) Seek(offset int64, whence int) (int64, error) {
|
||||
panic("don't call this in your unit test!")
|
||||
}
|
||||
|
||||
func (p2 *panickingUnionReader) Read(p []byte) (n int, err error) {
|
||||
panic("don't call this in your unit test!")
|
||||
}
|
||||
|
||||
func (p2 *panickingUnionReader) Close() error {
|
||||
panic("don't call this in your unit test!")
|
||||
}
|
||||
|
||||
var _ UnionReader = (*panickingUnionReader)(nil)
|
||||
|
||||
func Test_getUnionReader_fileLocationReadCloser(t *testing.T) {
|
||||
// panickingUnionReader is a UnionReader
|
||||
p := &panickingUnionReader{}
|
||||
embedsUnionReader := file.NewLocationReadCloser(file.Location{}, p)
|
||||
|
||||
// embedded union reader is returned without "ReadAll" invocation
|
||||
ur, err := GetUnionReader(embedsUnionReader)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, p, ur)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -156,7 +156,6 @@ func findReleases(resolver file.Resolver, dbPath string) []linux.Release {
|
||||
log.Tracef("unable to fetch contents for APK repositories file %q: %+v", reposLocation, err)
|
||||
return nil
|
||||
}
|
||||
defer internal.CloseAndLogError(reposReader, location.RealPath)
|
||||
|
||||
return parseReleasesFromAPKRepository(file.LocationReadCloser{
|
||||
Location: location,
|
||||
|
||||
@@ -4,96 +4,12 @@ Package arch provides a concrete Cataloger implementations for packages relating
|
||||
package arch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type cataloger struct {
|
||||
*generic.Cataloger
|
||||
}
|
||||
|
||||
// NewDBCataloger returns a new cataloger object initialized for arch linux pacman database flat-file stores.
|
||||
func NewDBCataloger() pkg.Cataloger {
|
||||
return cataloger{
|
||||
Cataloger: generic.NewCataloger("alpm-db-cataloger").
|
||||
WithParserByGlobs(parseAlpmDB, pkg.AlpmDBGlob),
|
||||
}
|
||||
}
|
||||
|
||||
func (c cataloger) Catalog(ctx context.Context, resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
pkgs, rels, err := c.Cataloger.Catalog(ctx, resolver)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
rels = append(rels, associateRelationships(pkgs)...)
|
||||
|
||||
return pkgs, rels, nil
|
||||
}
|
||||
|
||||
// associateRelationships will create relationships between packages based on the "Depends" and "Provides"
|
||||
// fields for installed packages. If there is an installed package that has a dependency that is (somehow) not installed,
|
||||
// then that relationship (between the installed and uninstalled package) will NOT be created.
|
||||
func associateRelationships(pkgs []pkg.Package) (relationships []artifact.Relationship) {
|
||||
// map["provides" + "package"] -> packages that provide that package
|
||||
lookup := make(map[string][]pkg.Package)
|
||||
|
||||
// read providers and add lookup keys as needed
|
||||
for _, p := range pkgs {
|
||||
meta, ok := p.Metadata.(pkg.AlpmDBEntry)
|
||||
if !ok {
|
||||
log.Warnf("cataloger failed to extract alpm 'provides' metadata for package %+v", p.Name)
|
||||
continue
|
||||
}
|
||||
// allow for lookup by package name
|
||||
lookup[p.Name] = append(lookup[p.Name], p)
|
||||
|
||||
for _, provides := range meta.Provides {
|
||||
// allow for lookup by exact specification
|
||||
lookup[provides] = append(lookup[provides], p)
|
||||
|
||||
// allow for lookup by library name only
|
||||
k := stripVersionSpecifier(provides)
|
||||
lookup[k] = append(lookup[k], p)
|
||||
}
|
||||
}
|
||||
|
||||
// read "Depends" and match with provider keys
|
||||
for _, p := range pkgs {
|
||||
meta, ok := p.Metadata.(pkg.AlpmDBEntry)
|
||||
if !ok {
|
||||
log.Warnf("cataloger failed to extract alpm 'dependency' metadata for package %+v", p.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, dep := range meta.Depends {
|
||||
for _, depPkg := range lookup[dep] {
|
||||
relationships = append(relationships, artifact.Relationship{
|
||||
From: depPkg,
|
||||
To: p,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return relationships
|
||||
}
|
||||
|
||||
func stripVersionSpecifier(s string) string {
|
||||
// examples:
|
||||
// gcc-libs --> gcc-libs
|
||||
// libtree-sitter.so=0-64 --> libtree-sitter.so
|
||||
|
||||
items := strings.Split(s, "=")
|
||||
if len(items) == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
return strings.TrimSpace(items[0])
|
||||
return generic.NewCataloger("alpm-db-cataloger").
|
||||
WithParserByGlobs(parseAlpmDB, pkg.AlpmDBGlob)
|
||||
}
|
||||
|
||||
@@ -12,289 +12,169 @@ import (
|
||||
)
|
||||
|
||||
func TestAlpmCataloger(t *testing.T) {
|
||||
gmpDbLocation := file.NewLocation("var/lib/pacman/local/gmp-6.2.1-2/desc")
|
||||
treeSitterDbLocation := file.NewLocation("var/lib/pacman/local/tree-sitter-0.22.6-1/desc")
|
||||
emacsDbLocation := file.NewLocation("var/lib/pacman/local/emacs-29.3-3/desc")
|
||||
fuzzyDbLocation := file.NewLocation("var/lib/pacman/local/fuzzy-1.2-3/desc")
|
||||
madeupDbLocation := file.NewLocation("var/lib/pacman/local/madeup-20.30-4/desc")
|
||||
|
||||
treeSitterPkg := pkg.Package{
|
||||
Name: "tree-sitter",
|
||||
Version: "0.22.6-1",
|
||||
Type: pkg.AlpmPkg,
|
||||
FoundBy: "alpm-db-cataloger",
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("MIT", treeSitterDbLocation),
|
||||
),
|
||||
Locations: file.NewLocationSet(treeSitterDbLocation),
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
BasePackage: "tree-sitter",
|
||||
Package: "tree-sitter",
|
||||
Version: "0.22.6-1",
|
||||
Description: "Incremental parsing library",
|
||||
Architecture: "x86_64",
|
||||
Size: 223539,
|
||||
Packager: "Daniel M. Capella <polyzen@archlinux.org>",
|
||||
URL: "https://github.com/tree-sitter/tree-sitter",
|
||||
Validation: "pgp",
|
||||
Reason: 1,
|
||||
Files: []pkg.AlpmFileRecord{},
|
||||
Backup: []pkg.AlpmFileRecord{},
|
||||
Provides: []string{"libtree-sitter.so=0-64"},
|
||||
},
|
||||
}
|
||||
|
||||
emacsPkg := pkg.Package{
|
||||
Name: "emacs",
|
||||
Version: "29.3-3",
|
||||
Type: pkg.AlpmPkg,
|
||||
FoundBy: "alpm-db-cataloger",
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("GPL3", emacsDbLocation),
|
||||
),
|
||||
Locations: file.NewLocationSet(emacsDbLocation),
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
BasePackage: "emacs",
|
||||
Package: "emacs",
|
||||
Version: "29.3-3",
|
||||
Description: "The extensible, customizable, self-documenting real-time display editor",
|
||||
Architecture: "x86_64",
|
||||
Size: 126427862,
|
||||
Packager: "Frederik Schwan <freswa@archlinux.org>",
|
||||
URL: "https://www.gnu.org/software/emacs/emacs.html",
|
||||
Validation: "pgp",
|
||||
Files: []pkg.AlpmFileRecord{},
|
||||
Backup: []pkg.AlpmFileRecord{},
|
||||
Depends: []string{"libtree-sitter.so=0-64"},
|
||||
},
|
||||
}
|
||||
|
||||
fuzzyPkg := pkg.Package{
|
||||
Name: "fuzzy",
|
||||
Version: "1.2-3",
|
||||
Type: pkg.AlpmPkg,
|
||||
FoundBy: "alpm-db-cataloger",
|
||||
Locations: file.NewLocationSet(
|
||||
fuzzyDbLocation,
|
||||
file.NewLocation("var/lib/pacman/local/fuzzy-1.2-3/files"),
|
||||
),
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Package: "fuzzy",
|
||||
Version: "1.2-3",
|
||||
Files: []pkg.AlpmFileRecord{},
|
||||
Backup: []pkg.AlpmFileRecord{
|
||||
{
|
||||
Path: "/etc/fuzzy.conf",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "79fce043df7dfc676ae5ecb903762d8b"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Depends: []string{"tree-sitter"},
|
||||
},
|
||||
}
|
||||
|
||||
madeupPkg := pkg.Package{
|
||||
Name: "madeup",
|
||||
Version: "20.30-4",
|
||||
Type: pkg.AlpmPkg,
|
||||
FoundBy: "alpm-db-cataloger",
|
||||
Locations: file.NewLocationSet(madeupDbLocation),
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Package: "madeup",
|
||||
Version: "20.30-4",
|
||||
Files: []pkg.AlpmFileRecord{},
|
||||
Backup: []pkg.AlpmFileRecord{},
|
||||
Depends: []string{"libtree-sitter.so"},
|
||||
},
|
||||
}
|
||||
|
||||
gmpPkg := pkg.Package{
|
||||
Name: "gmp",
|
||||
Version: "6.2.1-2",
|
||||
Type: pkg.AlpmPkg,
|
||||
FoundBy: "alpm-db-cataloger",
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("LGPL3", gmpDbLocation),
|
||||
pkg.NewLicenseFromLocations("GPL", gmpDbLocation),
|
||||
),
|
||||
Locations: file.NewLocationSet(
|
||||
gmpDbLocation,
|
||||
file.NewLocation("var/lib/pacman/local/gmp-6.2.1-2/files"),
|
||||
file.NewLocation("var/lib/pacman/local/gmp-6.2.1-2/mtree"),
|
||||
),
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
BasePackage: "gmp",
|
||||
Package: "gmp",
|
||||
Version: "6.2.1-2",
|
||||
Description: "A free library for arbitrary precision arithmetic",
|
||||
Architecture: "x86_64",
|
||||
Size: 1044438,
|
||||
Packager: "Antonio Rojas <arojas@archlinux.org>",
|
||||
URL: "https://gmplib.org/",
|
||||
Validation: "pgp",
|
||||
Reason: 1,
|
||||
Depends: []string{"gcc-libs", "sh", "libtree-sitter.so=1-64"},
|
||||
Files: []pkg.AlpmFileRecord{
|
||||
{
|
||||
Path: "/usr",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/include",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/include/gmp.h",
|
||||
Size: "84140",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "76595f70565c72550eb520809bf86856"},
|
||||
{Algorithm: "sha256", Value: "91a614b9202453153fe3b7512d15e89659108b93ce8841c8e13789eb85da9e3a"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/include/gmpxx.h",
|
||||
Size: "129113",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "ea3d21de4bcf7c696799c5c55dd3655b"},
|
||||
{Algorithm: "sha256", Value: "0011ae411a0bc1030e07d968b32fdc1343f5ac2a17b7d28f493e7976dde2ac82"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmp.so",
|
||||
Type: "link",
|
||||
Link: "libgmp.so.10.4.1",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmp.so.10",
|
||||
Type: "link",
|
||||
Link: "libgmp.so.10.4.1",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmp.so.10.4.1",
|
||||
Size: "663224",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "d6d03eadacdd9048d5b2adf577e9d722"},
|
||||
{Algorithm: "sha256", Value: "39898bd3d8d6785222432fa8b8aef7ce3b7e5bbfc66a52b7c0da09bed4adbe6a"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmpxx.so",
|
||||
Type: "link",
|
||||
Link: "libgmpxx.so.4.6.1",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmpxx.so.4",
|
||||
Type: "link",
|
||||
Link: "libgmpxx.so.4.6.1",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmpxx.so.4.6.1",
|
||||
Size: "30680",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "dd5f0c4d635fa599fa7f4339c0e8814d"},
|
||||
{Algorithm: "sha256", Value: "0ef67cbde4841f58d2e4b41f59425eb87c9eeaf4e649c060b326342c53bedbec"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/pkgconfig",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/pkgconfig/gmp.pc",
|
||||
Size: "245",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "a91a9f1b66218cb77b9cd2cdf341756d"},
|
||||
{Algorithm: "sha256", Value: "4e9de547a48c4e443781e9fa702a1ec5a23ee28b4bc520306cff2541a855be37"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/pkgconfig/gmpxx.pc",
|
||||
Size: "280",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "8c0f54e987934352177a6a30a811b001"},
|
||||
{Algorithm: "sha256", Value: "fc5dbfbe75977057ba50953d94b9daecf696c9fdfe5b94692b832b44ecca871b"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share/info",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share/info/gmp.info-1.gz",
|
||||
Size: "85892",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "63304d4d2f0247fb8a999fae66a81c19"},
|
||||
{Algorithm: "sha256", Value: "86288c1531a2789db5da8b9838b5cde4db07bda230ae11eba23a1f33698bd14e"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share/info/gmp.info-2.gz",
|
||||
Size: "48484",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "4bb0dadec416d305232cac6eae712ff7"},
|
||||
{Algorithm: "sha256", Value: "b7443c1b529588d98a074266087f79b595657ac7274191c34b10a9ceedfa950e"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share/info/gmp.info.gz",
|
||||
Size: "2380",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "cf6880fb0d862ee1da0d13c3831b5720"},
|
||||
{Algorithm: "sha256", Value: "a13c8eecda3f3e5ad1e09773e47a9686f07d9d494eaddf326f3696bbef1548fd"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Backup: []pkg.AlpmFileRecord{},
|
||||
},
|
||||
}
|
||||
|
||||
dbLocation := file.NewLocation("var/lib/pacman/local/gmp-6.2.1-2/desc")
|
||||
expectedPkgs := []pkg.Package{
|
||||
treeSitterPkg,
|
||||
emacsPkg,
|
||||
fuzzyPkg,
|
||||
madeupPkg,
|
||||
gmpPkg,
|
||||
{
|
||||
Name: "gmp",
|
||||
Version: "6.2.1-2",
|
||||
Type: pkg.AlpmPkg,
|
||||
FoundBy: "alpm-db-cataloger",
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("LGPL3", dbLocation),
|
||||
pkg.NewLicenseFromLocations("GPL", dbLocation),
|
||||
),
|
||||
Locations: file.NewLocationSet(dbLocation),
|
||||
CPEs: nil,
|
||||
PURL: "",
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
BasePackage: "gmp",
|
||||
Package: "gmp",
|
||||
Version: "6.2.1-2",
|
||||
Description: "A free library for arbitrary precision arithmetic",
|
||||
Architecture: "x86_64",
|
||||
Size: 1044438,
|
||||
Packager: "Antonio Rojas <arojas@archlinux.org>",
|
||||
URL: "https://gmplib.org/",
|
||||
Validation: "pgp",
|
||||
Reason: 1,
|
||||
Files: []pkg.AlpmFileRecord{
|
||||
{
|
||||
Path: "/usr",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/include",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/include/gmp.h",
|
||||
Size: "84140",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "76595f70565c72550eb520809bf86856"},
|
||||
{Algorithm: "sha256", Value: "91a614b9202453153fe3b7512d15e89659108b93ce8841c8e13789eb85da9e3a"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/include/gmpxx.h",
|
||||
Size: "129113",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "ea3d21de4bcf7c696799c5c55dd3655b"},
|
||||
{Algorithm: "sha256", Value: "0011ae411a0bc1030e07d968b32fdc1343f5ac2a17b7d28f493e7976dde2ac82"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmp.so",
|
||||
Type: "link",
|
||||
Link: "libgmp.so.10.4.1",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmp.so.10",
|
||||
Type: "link",
|
||||
Link: "libgmp.so.10.4.1",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmp.so.10.4.1",
|
||||
Size: "663224",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "d6d03eadacdd9048d5b2adf577e9d722"},
|
||||
{Algorithm: "sha256", Value: "39898bd3d8d6785222432fa8b8aef7ce3b7e5bbfc66a52b7c0da09bed4adbe6a"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmpxx.so",
|
||||
Type: "link",
|
||||
Link: "libgmpxx.so.4.6.1",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmpxx.so.4",
|
||||
Type: "link",
|
||||
Link: "libgmpxx.so.4.6.1",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/libgmpxx.so.4.6.1",
|
||||
Size: "30680",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "dd5f0c4d635fa599fa7f4339c0e8814d"},
|
||||
{Algorithm: "sha256", Value: "0ef67cbde4841f58d2e4b41f59425eb87c9eeaf4e649c060b326342c53bedbec"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/pkgconfig",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/pkgconfig/gmp.pc",
|
||||
Size: "245",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "a91a9f1b66218cb77b9cd2cdf341756d"},
|
||||
{Algorithm: "sha256", Value: "4e9de547a48c4e443781e9fa702a1ec5a23ee28b4bc520306cff2541a855be37"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/lib/pkgconfig/gmpxx.pc",
|
||||
Size: "280",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "8c0f54e987934352177a6a30a811b001"},
|
||||
{Algorithm: "sha256", Value: "fc5dbfbe75977057ba50953d94b9daecf696c9fdfe5b94692b832b44ecca871b"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share/info",
|
||||
Type: "dir",
|
||||
Digests: []file.Digest{},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share/info/gmp.info-1.gz",
|
||||
Size: "85892",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "63304d4d2f0247fb8a999fae66a81c19"},
|
||||
{Algorithm: "sha256", Value: "86288c1531a2789db5da8b9838b5cde4db07bda230ae11eba23a1f33698bd14e"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share/info/gmp.info-2.gz",
|
||||
Size: "48484",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "4bb0dadec416d305232cac6eae712ff7"},
|
||||
{Algorithm: "sha256", Value: "b7443c1b529588d98a074266087f79b595657ac7274191c34b10a9ceedfa950e"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/share/info/gmp.info.gz",
|
||||
Size: "2380",
|
||||
Digests: []file.Digest{
|
||||
{Algorithm: "md5", Value: "cf6880fb0d862ee1da0d13c3831b5720"},
|
||||
{Algorithm: "sha256", Value: "a13c8eecda3f3e5ad1e09773e47a9686f07d9d494eaddf326f3696bbef1548fd"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Backup: []pkg.AlpmFileRecord{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedRelationships := []artifact.Relationship{
|
||||
{ // exact spec lookup
|
||||
From: treeSitterPkg,
|
||||
To: emacsPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
{ // package name lookup
|
||||
From: treeSitterPkg,
|
||||
To: fuzzyPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
{ // library name lookup
|
||||
From: treeSitterPkg,
|
||||
To: madeupPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
}
|
||||
// TODO: relationships are not under test yet
|
||||
var expectedRelationships []artifact.Relationship
|
||||
|
||||
pkgtest.NewCatalogTester().
|
||||
FromDirectory(t, "test-fixtures/installed").
|
||||
FromDirectory(t, "test-fixtures/gmp-fixture").
|
||||
WithCompareOptions(cmpopts.IgnoreFields(pkg.AlpmFileRecord{}, "Time")).
|
||||
Expects(expectedPkgs, expectedRelationships).
|
||||
TestCataloger(t, NewDBCataloger())
|
||||
|
||||
@@ -9,16 +9,13 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func newPackage(m *parsedData, release *linux.Release, dbLocation file.Location, otherLocations ...file.Location) pkg.Package {
|
||||
func newPackage(m *parsedData, release *linux.Release, dbLocation file.Location) pkg.Package {
|
||||
licenseCandidates := strings.Split(m.Licenses, "\n")
|
||||
|
||||
locs := file.NewLocationSet(dbLocation)
|
||||
locs.Add(otherLocations...)
|
||||
|
||||
p := pkg.Package{
|
||||
Name: m.Package,
|
||||
Version: m.Version,
|
||||
Locations: locs,
|
||||
Locations: file.NewLocationSet(dbLocation),
|
||||
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocation(dbLocation.WithoutAnnotations(), licenseCandidates...)...),
|
||||
Type: pkg.AlpmPkg,
|
||||
PURL: packageURL(m, release),
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -15,8 +14,6 @@ import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/vbatts/go-mtree"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -46,26 +43,33 @@ func parseAlpmDB(_ context.Context, resolver file.Resolver, env *generic.Environ
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
return nil, nil, nil
|
||||
base := filepath.Dir(reader.RealPath)
|
||||
r, err := getFileReader(filepath.Join(base, "mtree"), resolver)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
base := path.Dir(reader.RealPath)
|
||||
pkgFiles, err := parseMtree(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// replace the files found the pacman database with the files from the mtree These contain more metadata and
|
||||
// thus more useful.
|
||||
files, fileLoc := fetchPkgFiles(base, resolver)
|
||||
backups, backupLoc := fetchBackupFiles(base, resolver)
|
||||
// TODO: probably want to use MTREE and PKGINFO here
|
||||
data.Files = pkgFiles
|
||||
|
||||
var locs []file.Location
|
||||
if fileLoc != nil {
|
||||
locs = append(locs, fileLoc.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation))
|
||||
data.Files = files
|
||||
// We only really do this to get any backup database entries from the files database
|
||||
files := filepath.Join(base, "files")
|
||||
_, err = getFileReader(files, resolver)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if backupLoc != nil {
|
||||
locs = append(locs, backupLoc.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation))
|
||||
data.Backup = backups
|
||||
filesMetadata, err := parseAlpmDBEntry(reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else if filesMetadata != nil {
|
||||
data.Backup = filesMetadata.Backup
|
||||
}
|
||||
|
||||
if data.Package == "" {
|
||||
@@ -77,67 +81,10 @@ func parseAlpmDB(_ context.Context, resolver file.Resolver, env *generic.Environ
|
||||
data,
|
||||
env.LinuxRelease,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
locs...,
|
||||
),
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
func fetchPkgFiles(base string, resolver file.Resolver) ([]pkg.AlpmFileRecord, *file.Location) {
|
||||
// TODO: probably want to use MTREE and PKGINFO here
|
||||
target := path.Join(base, "mtree")
|
||||
|
||||
loc, err := getLocation(target, resolver)
|
||||
if err != nil {
|
||||
log.WithFields("error", err, "path", target).Trace("failed to find mtree file")
|
||||
return []pkg.AlpmFileRecord{}, nil
|
||||
}
|
||||
if loc == nil {
|
||||
return []pkg.AlpmFileRecord{}, nil
|
||||
}
|
||||
|
||||
reader, err := resolver.FileContentsByLocation(*loc)
|
||||
if err != nil {
|
||||
return []pkg.AlpmFileRecord{}, nil
|
||||
}
|
||||
defer internal.CloseAndLogError(reader, loc.RealPath)
|
||||
|
||||
pkgFiles, err := parseMtree(reader)
|
||||
if err != nil {
|
||||
log.WithFields("error", err, "path", target).Trace("failed to parse mtree file")
|
||||
return []pkg.AlpmFileRecord{}, nil
|
||||
}
|
||||
return pkgFiles, loc
|
||||
}
|
||||
|
||||
func fetchBackupFiles(base string, resolver file.Resolver) ([]pkg.AlpmFileRecord, *file.Location) {
|
||||
// We only really do this to get any backup database entries from the files database
|
||||
target := filepath.Join(base, "files")
|
||||
|
||||
loc, err := getLocation(target, resolver)
|
||||
if err != nil {
|
||||
log.WithFields("error", err, "path", target).Trace("failed to find alpm files")
|
||||
return []pkg.AlpmFileRecord{}, nil
|
||||
}
|
||||
if loc == nil {
|
||||
return []pkg.AlpmFileRecord{}, nil
|
||||
}
|
||||
|
||||
reader, err := resolver.FileContentsByLocation(*loc)
|
||||
if err != nil {
|
||||
return []pkg.AlpmFileRecord{}, nil
|
||||
}
|
||||
defer internal.CloseAndLogError(reader, loc.RealPath)
|
||||
|
||||
filesMetadata, err := parseAlpmDBEntry(reader)
|
||||
if err != nil {
|
||||
return []pkg.AlpmFileRecord{}, nil
|
||||
}
|
||||
if filesMetadata != nil {
|
||||
return filesMetadata.Backup, loc
|
||||
}
|
||||
return []pkg.AlpmFileRecord{}, loc
|
||||
}
|
||||
|
||||
func parseAlpmDBEntry(reader io.Reader) (*parsedData, error) {
|
||||
scanner := newScanner(reader)
|
||||
metadata, err := parseDatabase(scanner)
|
||||
@@ -171,7 +118,7 @@ func newScanner(reader io.Reader) *bufio.Scanner {
|
||||
return scanner
|
||||
}
|
||||
|
||||
func getLocation(path string, resolver file.Resolver) (*file.Location, error) {
|
||||
func getFileReader(path string, resolver file.Resolver) (io.Reader, error) {
|
||||
locs, err := resolver.FilesByPath(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -180,11 +127,12 @@ func getLocation(path string, resolver file.Resolver) (*file.Location, error) {
|
||||
if len(locs) == 0 {
|
||||
return nil, fmt.Errorf("could not find file: %s", path)
|
||||
}
|
||||
|
||||
if len(locs) > 1 {
|
||||
log.WithFields("path", path).Trace("multiple files found for path, using first path")
|
||||
// TODO: Should we maybe check if we found the file
|
||||
dbContentReader, err := resolver.FileContentsByLocation(locs[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &locs[0], nil
|
||||
return dbContentReader, nil
|
||||
}
|
||||
|
||||
func parseDatabase(b *bufio.Scanner) (*parsedData, error) {
|
||||
@@ -207,9 +155,9 @@ func parseDatabase(b *bufio.Scanner) (*parsedData, error) {
|
||||
case "files":
|
||||
var files []map[string]string
|
||||
for _, f := range strings.Split(value, "\n") {
|
||||
p := fmt.Sprintf("/%s", f)
|
||||
if ok := ignoredFiles[p]; !ok {
|
||||
files = append(files, map[string]string{"path": p})
|
||||
path := fmt.Sprintf("/%s", f)
|
||||
if ok := ignoredFiles[path]; !ok {
|
||||
files = append(files, map[string]string{"path": path})
|
||||
}
|
||||
}
|
||||
pkgFields[key] = files
|
||||
@@ -217,10 +165,10 @@ func parseDatabase(b *bufio.Scanner) (*parsedData, error) {
|
||||
var backup []map[string]interface{}
|
||||
for _, f := range strings.Split(value, "\n") {
|
||||
fields := strings.SplitN(f, "\t", 2)
|
||||
p := fmt.Sprintf("/%s", fields[0])
|
||||
if ok := ignoredFiles[p]; !ok {
|
||||
path := fmt.Sprintf("/%s", fields[0])
|
||||
if ok := ignoredFiles[path]; !ok {
|
||||
backup = append(backup, map[string]interface{}{
|
||||
"path": p,
|
||||
"path": path,
|
||||
"digests": []file.Digest{{
|
||||
Algorithm: "md5",
|
||||
Value: fields[1],
|
||||
@@ -228,8 +176,6 @@ func parseDatabase(b *bufio.Scanner) (*parsedData, error) {
|
||||
}
|
||||
}
|
||||
pkgFields[key] = backup
|
||||
case "depends", "provides":
|
||||
pkgFields[key] = processLibrarySpecs(value)
|
||||
case "reason":
|
||||
fallthrough
|
||||
case "size":
|
||||
@@ -245,19 +191,6 @@ func parseDatabase(b *bufio.Scanner) (*parsedData, error) {
|
||||
return parsePkgFiles(pkgFields)
|
||||
}
|
||||
|
||||
func processLibrarySpecs(value string) []string {
|
||||
lines := strings.Split(value, "\n")
|
||||
librarySpecs := make([]string, 0)
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
librarySpecs = append(librarySpecs, line)
|
||||
}
|
||||
return librarySpecs
|
||||
}
|
||||
|
||||
func parsePkgFiles(pkgFields map[string]interface{}) (*parsedData, error) {
|
||||
var entry parsedData
|
||||
if err := mapstructure.Decode(pkgFields, &entry); err != nil {
|
||||
@@ -268,10 +201,6 @@ func parsePkgFiles(pkgFields map[string]interface{}) (*parsedData, error) {
|
||||
entry.Backup = make([]pkg.AlpmFileRecord, 0)
|
||||
}
|
||||
|
||||
if entry.Files == nil {
|
||||
entry.Files = make([]pkg.AlpmFileRecord, 0)
|
||||
}
|
||||
|
||||
if entry.Package == "" && len(entry.Files) == 0 && len(entry.Backup) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -17,120 +17,74 @@ func TestDatabaseParser(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
expected *parsedData
|
||||
expected pkg.AlpmDBEntry
|
||||
}{
|
||||
{
|
||||
name: "simple desc parsing",
|
||||
name: "test alpm database parsing",
|
||||
fixture: "test-fixtures/files",
|
||||
expected: &parsedData{
|
||||
AlpmDBEntry: pkg.AlpmDBEntry{
|
||||
Backup: []pkg.AlpmFileRecord{
|
||||
{
|
||||
Path: "/etc/pacman.conf",
|
||||
Digests: []file.Digest{{
|
||||
Algorithm: "md5",
|
||||
Value: "de541390e52468165b96511c4665bff4",
|
||||
}},
|
||||
},
|
||||
{
|
||||
Path: "/etc/makepkg.conf",
|
||||
Digests: []file.Digest{{
|
||||
Algorithm: "md5",
|
||||
Value: "79fce043df7dfc676ae5ecb903762d8b",
|
||||
}},
|
||||
},
|
||||
expected: pkg.AlpmDBEntry{
|
||||
Backup: []pkg.AlpmFileRecord{
|
||||
{
|
||||
Path: "/etc/pacman.conf",
|
||||
Digests: []file.Digest{{
|
||||
Algorithm: "md5",
|
||||
Value: "de541390e52468165b96511c4665bff4",
|
||||
}},
|
||||
},
|
||||
Files: []pkg.AlpmFileRecord{
|
||||
{
|
||||
Path: "/etc/",
|
||||
},
|
||||
{
|
||||
Path: "/etc/makepkg.conf",
|
||||
},
|
||||
{
|
||||
Path: "/etc/pacman.conf",
|
||||
},
|
||||
{
|
||||
Path: "/usr/",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/makepkg",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/makepkg-template",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/pacman",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/pacman-conf",
|
||||
},
|
||||
{
|
||||
Path: "/var/",
|
||||
},
|
||||
{
|
||||
Path: "/var/cache/",
|
||||
},
|
||||
{
|
||||
Path: "/var/cache/pacman/",
|
||||
},
|
||||
{
|
||||
Path: "/var/cache/pacman/pkg/",
|
||||
},
|
||||
{
|
||||
Path: "/var/lib/",
|
||||
},
|
||||
{
|
||||
Path: "/var/lib/pacman/",
|
||||
},
|
||||
{
|
||||
Path: "/etc/makepkg.conf",
|
||||
Digests: []file.Digest{{
|
||||
Algorithm: "md5",
|
||||
Value: "79fce043df7dfc676ae5ecb903762d8b",
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with dependencies",
|
||||
fixture: "test-fixtures/installed/var/lib/pacman/local/gmp-6.2.1-2/desc",
|
||||
expected: &parsedData{
|
||||
Licenses: "LGPL3\nGPL",
|
||||
AlpmDBEntry: pkg.AlpmDBEntry{
|
||||
BasePackage: "gmp",
|
||||
Package: "gmp",
|
||||
Version: "6.2.1-2",
|
||||
Description: "A free library for arbitrary precision arithmetic",
|
||||
Architecture: "x86_64",
|
||||
Size: 1044438,
|
||||
Packager: "Antonio Rojas <arojas@archlinux.org>",
|
||||
URL: "https://gmplib.org/",
|
||||
Validation: "pgp",
|
||||
Reason: 1,
|
||||
Files: []pkg.AlpmFileRecord{},
|
||||
Backup: []pkg.AlpmFileRecord{},
|
||||
Depends: []string{"gcc-libs", "sh", "libtree-sitter.so=1-64"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with provides",
|
||||
fixture: "test-fixtures/installed/var/lib/pacman/local/tree-sitter-0.22.6-1/desc",
|
||||
expected: &parsedData{
|
||||
Licenses: "MIT",
|
||||
AlpmDBEntry: pkg.AlpmDBEntry{
|
||||
BasePackage: "tree-sitter",
|
||||
Package: "tree-sitter",
|
||||
Version: "0.22.6-1",
|
||||
Description: "Incremental parsing library",
|
||||
Architecture: "x86_64",
|
||||
Size: 223539,
|
||||
Packager: "Daniel M. Capella <polyzen@archlinux.org>",
|
||||
URL: "https://github.com/tree-sitter/tree-sitter",
|
||||
Validation: "pgp",
|
||||
Reason: 1,
|
||||
Files: []pkg.AlpmFileRecord{},
|
||||
Backup: []pkg.AlpmFileRecord{},
|
||||
Provides: []string{"libtree-sitter.so=0-64"},
|
||||
Files: []pkg.AlpmFileRecord{
|
||||
{
|
||||
Path: "/etc/",
|
||||
},
|
||||
{
|
||||
Path: "/etc/makepkg.conf",
|
||||
},
|
||||
{
|
||||
Path: "/etc/pacman.conf",
|
||||
},
|
||||
{
|
||||
Path: "/usr/",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/makepkg",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/makepkg-template",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/pacman",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/pacman-conf",
|
||||
},
|
||||
{
|
||||
Path: "/var/",
|
||||
},
|
||||
{
|
||||
Path: "/var/cache/",
|
||||
},
|
||||
{
|
||||
Path: "/var/cache/pacman/",
|
||||
},
|
||||
{
|
||||
Path: "/var/cache/pacman/pkg/",
|
||||
},
|
||||
{
|
||||
Path: "/var/lib/",
|
||||
},
|
||||
{
|
||||
Path: "/var/lib/pacman/",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -147,10 +101,13 @@ func TestDatabaseParser(t *testing.T) {
|
||||
entry, err := parseAlpmDBEntry(reader)
|
||||
require.NoError(t, err)
|
||||
|
||||
if diff := cmp.Diff(test.expected, entry); diff != "" {
|
||||
t.Errorf("parsed data mismatch (-want +got):\n%s", diff)
|
||||
if diff := cmp.Diff(entry.Files, test.expected.Files); diff != "" {
|
||||
t.Errorf("Files mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(entry.Backup, test.expected.Backup); diff != "" {
|
||||
t.Errorf("Backup mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -41,4 +41,4 @@ pgp
|
||||
%DEPENDS%
|
||||
gcc-libs
|
||||
sh
|
||||
libtree-sitter.so=1-64
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
%NAME%
|
||||
emacs
|
||||
|
||||
%VERSION%
|
||||
29.3-3
|
||||
|
||||
%BASE%
|
||||
emacs
|
||||
|
||||
%DESC%
|
||||
The extensible, customizable, self-documenting real-time display editor
|
||||
|
||||
%URL%
|
||||
https://www.gnu.org/software/emacs/emacs.html
|
||||
|
||||
%ARCH%
|
||||
x86_64
|
||||
|
||||
%BUILDDATE%
|
||||
1714249917
|
||||
|
||||
%INSTALLDATE%
|
||||
1715026363
|
||||
|
||||
%PACKAGER%
|
||||
Frederik Schwan <freswa@archlinux.org>
|
||||
|
||||
%SIZE%
|
||||
126427862
|
||||
|
||||
%LICENSE%
|
||||
GPL3
|
||||
|
||||
%VALIDATION%
|
||||
pgp
|
||||
|
||||
%DEPENDS%
|
||||
libtree-sitter.so=0-64
|
||||
@@ -1,8 +0,0 @@
|
||||
%NAME%
|
||||
fuzzy
|
||||
|
||||
%VERSION%
|
||||
1.2-3
|
||||
|
||||
%DEPENDS%
|
||||
tree-sitter
|
||||
@@ -1,6 +0,0 @@
|
||||
%FILES%
|
||||
etc/
|
||||
etc/fuzzy.conf
|
||||
|
||||
%BACKUP%
|
||||
etc/fuzzy.conf 79fce043df7dfc676ae5ecb903762d8b
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
%NAME%
|
||||
madeup
|
||||
|
||||
%VERSION%
|
||||
20.30-4
|
||||
|
||||
%DEPENDS%
|
||||
libtree-sitter.so
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
%NAME%
|
||||
tree-sitter
|
||||
|
||||
%VERSION%
|
||||
0.22.6-1
|
||||
|
||||
%BASE%
|
||||
tree-sitter
|
||||
|
||||
%DESC%
|
||||
Incremental parsing library
|
||||
|
||||
%URL%
|
||||
https://github.com/tree-sitter/tree-sitter
|
||||
|
||||
%ARCH%
|
||||
x86_64
|
||||
|
||||
%BUILDDATE%
|
||||
1714945746
|
||||
|
||||
%INSTALLDATE%
|
||||
1715026360
|
||||
|
||||
%PACKAGER%
|
||||
Daniel M. Capella <polyzen@archlinux.org>
|
||||
|
||||
%SIZE%
|
||||
223539
|
||||
|
||||
%REASON%
|
||||
1
|
||||
|
||||
%LICENSE%
|
||||
MIT
|
||||
|
||||
%VALIDATION%
|
||||
pgp
|
||||
|
||||
%PROVIDES%
|
||||
libtree-sitter.so=0-64
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/internal/unionreader"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
@@ -230,10 +231,14 @@ func getContents(resolver file.Resolver, location file.Location) ([]byte, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer internal.CloseAndLogError(reader, location.AccessPath)
|
||||
|
||||
unionReader, err := unionreader.GetUnionReader(reader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get union reader for file: %w", err)
|
||||
}
|
||||
|
||||
// TODO: there may be room for improvement here, as this may use an excessive amount of memory. Alternate approach is to leverage a RuneReader.
|
||||
contents, err := io.ReadAll(reader)
|
||||
contents, err := io.ReadAll(unionReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get contents for file: %w", err)
|
||||
}
|
||||
|
||||
@@ -37,17 +37,6 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
logicalFixture string
|
||||
expected pkg.Package
|
||||
}{
|
||||
{
|
||||
logicalFixture: "arangodb/3.11.8/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "arangodb",
|
||||
Version: "3.11.8",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/arangodb@3.11.8",
|
||||
Locations: locations("arangosh"),
|
||||
Metadata: metadata("arangodb-binary"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "postgres/15beta4/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
@@ -854,7 +843,7 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "erlang/25.3.2.6/linux-amd64",
|
||||
logicalFixture: "erlexec/25.3.2.6/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "erlang",
|
||||
Version: "25.3.2.6",
|
||||
@@ -865,7 +854,7 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "erlang/26.2.0.0/linux-amd64",
|
||||
logicalFixture: "erlexec/26.2.0.0/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "erlang",
|
||||
Version: "26.2",
|
||||
@@ -875,17 +864,6 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
Metadata: metadata("erlang-binary"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "erlang/26.2.4/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "erlang",
|
||||
Version: "26.2.4",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/erlang@26.2.4",
|
||||
Locations: locations("liberts_internal.a"),
|
||||
Metadata: metadata("erlang-library"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "nginx/1.25.1/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
|
||||
@@ -246,7 +246,6 @@ func DefaultClassifiers() []Classifier {
|
||||
`(?m)memcached\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
||||
Package: "memcached",
|
||||
PURL: mustPURL("pkg:generic/memcached@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:memcached:memcached:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "traefik-binary",
|
||||
@@ -257,16 +256,6 @@ func DefaultClassifiers() []Classifier {
|
||||
`(?m)(\x00|\x{FFFD})v?(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-alpha[0-9]|-beta[0-9]|-rc[0-9])?)\x00`),
|
||||
Package: "traefik",
|
||||
PURL: mustPURL("pkg:generic/traefik@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:traefik:traefik:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "arangodb-binary",
|
||||
FileGlob: "**/arangosh",
|
||||
EvidenceMatcher: FileContentsVersionMatcher(
|
||||
`(?m)ArangoDB\s\x00*(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\s\[linux\]`),
|
||||
Package: "arangodb",
|
||||
PURL: mustPURL("pkg:generic/arangodb@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:arangodb:arangodb:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "postgresql-binary",
|
||||
@@ -279,7 +268,6 @@ func DefaultClassifiers() []Classifier {
|
||||
`(?m)(\x00|\?)PostgreSQL (?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`),
|
||||
Package: "postgresql",
|
||||
PURL: mustPURL("pkg:generic/postgresql@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:postgresql:postgresql:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "mysql-binary",
|
||||
@@ -373,28 +361,11 @@ func DefaultClassifiers() []Classifier {
|
||||
EvidenceMatcher: evidenceMatchers(
|
||||
FileContentsVersionMatcher(
|
||||
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
|
||||
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+\.[0-9]+)?)/erts/`,
|
||||
),
|
||||
FileContentsVersionMatcher(
|
||||
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
|
||||
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||
),
|
||||
),
|
||||
Package: "erlang",
|
||||
PURL: mustPURL("pkg:generic/erlang@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "erlang-library",
|
||||
FileGlob: "**/liberts_internal.a",
|
||||
EvidenceMatcher: evidenceMatchers(
|
||||
FileContentsVersionMatcher(
|
||||
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
|
||||
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||
),
|
||||
FileContentsVersionMatcher(
|
||||
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
|
||||
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+\.[0-9]+)?)/erts/`,
|
||||
),
|
||||
),
|
||||
Package: "erlang",
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/mimetype"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
@@ -58,13 +57,31 @@ func (c *elfPackageCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
||||
// first find all ELF binaries that have notes
|
||||
var notesByLocation = make(map[elfPackageKey][]elfBinaryPackageNotes)
|
||||
for _, location := range locations {
|
||||
notes, key, err := parseElfPackageNotes(resolver, location, c)
|
||||
reader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, fmt.Errorf("unable to get binary contents %q: %w", location.Path(), err)
|
||||
}
|
||||
|
||||
notes, err := c.parseElfNotes(file.LocationReadCloser{
|
||||
Location: location,
|
||||
ReadCloser: reader,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithFields("file", location.Path(), "error", err).Trace("unable to parse ELF notes")
|
||||
continue
|
||||
}
|
||||
|
||||
if notes == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
notes.Location = location
|
||||
key := elfPackageKey{
|
||||
Name: notes.Name,
|
||||
Version: notes.Version,
|
||||
PURL: notes.PURL,
|
||||
CPE: notes.CPE,
|
||||
}
|
||||
notesByLocation[key] = append(notesByLocation[key], *notes)
|
||||
}
|
||||
|
||||
@@ -88,37 +105,6 @@ func (c *elfPackageCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
func parseElfPackageNotes(resolver file.Resolver, location file.Location, c *elfPackageCataloger) (*elfBinaryPackageNotes, elfPackageKey, error) {
|
||||
reader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
return nil, elfPackageKey{}, fmt.Errorf("unable to get binary contents %q: %w", location.Path(), err)
|
||||
}
|
||||
defer internal.CloseAndLogError(reader, location.AccessPath)
|
||||
|
||||
notes, err := c.parseElfNotes(file.LocationReadCloser{
|
||||
Location: location,
|
||||
ReadCloser: reader,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.WithFields("file", location.Path(), "error", err).Trace("unable to parse ELF notes")
|
||||
return nil, elfPackageKey{}, nil
|
||||
}
|
||||
|
||||
if notes == nil {
|
||||
return nil, elfPackageKey{}, nil
|
||||
}
|
||||
|
||||
notes.Location = location
|
||||
key := elfPackageKey{
|
||||
Name: notes.Name,
|
||||
Version: notes.Version,
|
||||
PURL: notes.PURL,
|
||||
CPE: notes.CPE,
|
||||
}
|
||||
return notes, key, nil
|
||||
}
|
||||
|
||||
func (c *elfPackageCataloger) parseElfNotes(reader file.LocationReadCloser) (*elfBinaryPackageNotes, error) {
|
||||
metadata, err := getELFNotes(reader)
|
||||
if err != nil {
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -31,30 +31,20 @@ from-images:
|
||||
paths:
|
||||
- /usr/local/bin/gcc
|
||||
|
||||
- name: erlang
|
||||
version: 25.3.2.6
|
||||
- version: 25.3.2.6
|
||||
images:
|
||||
- ref: erlang:25.3.2.6@sha256:0d1e530ec0e8047094f0a1d841754515bad9b0554260a3147fb34df31b3064fe
|
||||
platform: linux/amd64
|
||||
paths:
|
||||
- /usr/local/lib/erlang/erts-13.2.2.3/bin/erlexec
|
||||
|
||||
- name: erlang
|
||||
version: 26.2.0.0
|
||||
- version: 26.2.0.0
|
||||
images:
|
||||
- ref: erlang:26.2.0.0@sha256:31c3aa505fbe7526ca83c57b64e56ba505e62733e7e6518f4c06219de6e7396e
|
||||
platform: linux/amd64
|
||||
paths:
|
||||
- /usr/local/lib/erlang/erts-14.2/bin/erlexec
|
||||
|
||||
- name: erlang
|
||||
version: 26.2.4
|
||||
images:
|
||||
- ref: erlang:26.2.4.0@sha256:bdb5bac0612856ec85982171dcd4a11de2e08e7f7469c86f3eb936bdfd1ec204
|
||||
platform: linux/amd64
|
||||
paths:
|
||||
- /usr/local/lib/erlang/erts-14.2.4/lib/internal/liberts_internal.a
|
||||
|
||||
- version: 1.21.3
|
||||
images:
|
||||
- ref: golang:1.21.3@sha256:3ce8313c3513515040870c55e0c041a2b94f3576a58cfd3948633604214aa811
|
||||
@@ -270,13 +260,6 @@ from-images:
|
||||
# paths:
|
||||
# - /usr/bin/perl
|
||||
|
||||
- name: arangodb
|
||||
version: 3.11.8
|
||||
images:
|
||||
- ref: arangodb:3.11.8@sha256:16893e767f47d28e3297839637741e5c4023e815adf860dfc674e1a36c7c7db0
|
||||
platform: linux/amd64
|
||||
paths:
|
||||
- /usr/bin/arangosh
|
||||
- version: 15.1
|
||||
images:
|
||||
- ref: postgres:15.1@sha256:b4140dd3a62f364f16a82c1bd88d28b9887ecb47f07dbe2941237d073574d428
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
## Summary
|
||||
This image illustrates a few examples of how ELF executables can be assembled and illustrated in an SBOM.
|
||||
|
||||
### Example 1: elf-test-fixtures/elfbinwithsisterlib
|
||||
This example builds two binaries with srcs found in elfsrc1 and elfsrc2.
|
||||
|
||||
|
||||
|
||||
- 3 separate libs, two with the same name, 1 different, all different locations, but same output when:
|
||||
|
||||
|
||||
|
||||
```
|
||||
objdump -s -j .note.package /usr/local/bin/elftests/elfbinwithnestedlib/bin/lib/libhello_world.so
|
||||
|
||||
/usr/local/bin/elftests/elfbinwithnestedlib/bin/lib/libhello_world.so: file format elf64-littleaarch64
|
||||
|
||||
Contents of section .note.package:
|
||||
0000 7b227479 7065223a 20227465 73746669 {"type": "testfi
|
||||
0010 78747572 65222c22 6c696365 6e736522 xture","license"
|
||||
0020 3a224d49 54222c22 636f6d6d 6974223a :"MIT","commit":
|
||||
0030 22353533 34633338 64306666 65663961 "5534c38d0ffef9a
|
||||
0040 33663833 31353466 30623761 37666236 3f83154f0b7a7fb6
|
||||
0050 61623061 62366462 62222c22 736f7572 ab0ab6dbb","sour
|
||||
0060 63655265 706f223a 22687474 70733a2f ceRepo":"https:/
|
||||
0070 2f676974 6875622e 636f6d2f 736f6d65 /github.com/some
|
||||
0080 6f6e652f 736f6d65 77686572 652e6769 one/somewhere.gi
|
||||
0090 74222c22 76656e64 6f72223a 20227379 t","vendor": "sy
|
||||
00a0 6674222c 22737973 74656d22 3a202273 ft","system": "s
|
||||
00b0 79667473 7973222c 226e616d 65223a20 yftsys","name":
|
||||
00c0 226c6962 68656c6c 6f5f776f 726c642e "libhello_world.
|
||||
00d0 736f222c 22766572 73696f6e 223a2022 so","version": "
|
||||
00e0 302e3031 222c2270 75726c22 3a202270 0.01","purl": "p
|
||||
00f0 6b673a67 656e6572 69632f73 79667473 kg:generic/syfts
|
||||
0100 79732f73 79667474 65737466 69787475 ys/syfttestfixtu
|
||||
0110 72654030 2e303122 2c226370 65223a20 re@0.01","cpe":
|
||||
0120 22637065 3a2f6f3a 73796674 3a737966 "cpe:/o:syft:syf
|
||||
0130 74737973 5f746573 74666978 74757265 tsys_testfixture
|
||||
0140 5f737966 74746573 74666978 74757265 _syfttestfixture
|
||||
0150 3a302e30 31227d0a :0.01"}.
|
||||
```
|
||||
|
||||
### Binaries
|
||||
```
|
||||
/usr/local/bin/elftests/elfbinwithnestedlib/bin/elfbinwithnestedlib
|
||||
/usr/local/bin/elftests/elfbinwithsisterlib/bin/elfwithparallellibbin2
|
||||
/usr/local/bin/elftests/elfbinwithsisterlib/bin/elfwithparallellibbin1
|
||||
```
|
||||
|
||||
#### Libraries
|
||||
```
|
||||
/usr/local/bin/elftests/elfbinwithnestedlib/bin/lib/libhello_world.so
|
||||
/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world.so
|
||||
/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world2.so
|
||||
```
|
||||
|
||||
#### Binaries related to Libraries
|
||||
The resulting SBOM shoult show the following relationships:
|
||||
```
|
||||
elfbinwithnestedlib -> libhello_world.so
|
||||
elfwithparallellibbin2 -> libhello_world.so
|
||||
elfwithparallellibbin1 -> libhello_world2.so
|
||||
```
|
||||
#### Desired State
|
||||
We want to drop the package to file relationships and instead do package to package
|
||||
|
||||
Single relationship
|
||||
ElfPackage `libhellp_world.so` -> ElfPackage `syfttestfixture` library
|
||||
|
||||
Also relationship between the binaries and the rpm packages transitive dependencies that come from the library
|
||||
|
||||
#### Actual state
|
||||
```mermaid
|
||||
flowchart
|
||||
nested(.../bin/elfbinwithnestedlib)
|
||||
parallel1(.../bin/elfwithparallellibbin1)
|
||||
parallel2(.../bin/elfwithparallellibbin2)
|
||||
|
||||
nestedLib(.../nested/bin/lib/libhello_world.so)
|
||||
sisterLib1(.../sister/lib/libhello_world.so)
|
||||
sisterLib2(.../sister/lib/libhello_world2.so)
|
||||
|
||||
libc(libc.so.6)
|
||||
libstdc(libstdc++.so.6)
|
||||
|
||||
nested --> |imports ../bin/lib/libhello_world.so| nestedLib
|
||||
nested --> |imports libhello_world.so| sisterLib1
|
||||
nested --> |imports libstdc++.so.6| libstdc
|
||||
nested --> |imports libc.so.6| libc
|
||||
|
||||
nestedLib --> |imports libc.so.6| libc
|
||||
sisterLib1 --> |imports libc.so.6| libc
|
||||
|
||||
parallel1 --> nestedLib
|
||||
parallel1 --> sisterLib1
|
||||
parallel1 --> libstdc
|
||||
parallel1 --> libc
|
||||
|
||||
parallel2 --> |imports ../lib/libhello_world2.so| sisterLib2
|
||||
parallel2 --> |imports libhello_world2.so| sisterLib2
|
||||
parallel2 --> libstdc
|
||||
parallel2 --> libc
|
||||
|
||||
|
||||
sisterLib2 --> libc
|
||||
```
|
||||
|
||||
#### Desired relationships
|
||||
```mermaid
|
||||
flowchart LR
|
||||
%% Data sync workflow...
|
||||
|
||||
subgraph logicalAppPackage [ELF Package - 'syfttestfixture']
|
||||
nested(.../bin/elfbinwithnestedlib)
|
||||
parallel1(.../bin/elfwithparallellibbin1)
|
||||
parallel2(.../bin/elfwithparallellibbin2)
|
||||
end
|
||||
|
||||
|
||||
subgraph logicalLibPackage [ELF Package - 'libhello_world.so']
|
||||
nestedLib(.../nested/bin/lib/libhello_world.so)
|
||||
sisterLib1(.../sister/lib/libhello_world.so)
|
||||
sisterLib2(.../sister/lib/libhello_world2.so)
|
||||
end
|
||||
|
||||
|
||||
logicalLibPackage --> |dependency-of| logicalAppPackage
|
||||
|
||||
|
||||
%% RPM packages
|
||||
|
||||
libstdc(libstdc++) --> |dependency-of| logicalAppPackage
|
||||
glibc(glibc) --> |dependency-of| logicalAppPackage
|
||||
glibc(glibc) --> |dependency-of| logicalLibPackage
|
||||
```
|
||||
@@ -10,6 +10,6 @@ func Generate(p pkg.Package) []cpe.CPE {
|
||||
return cpegenerate.FromPackageAttributes(p)
|
||||
}
|
||||
|
||||
func DictionaryFind(p pkg.Package) ([]cpe.CPE, bool) {
|
||||
func DictionaryFind(p pkg.Package) (cpe.CPE, bool) {
|
||||
return cpegenerate.FromDictionaryFind(p)
|
||||
}
|
||||
|
||||
@@ -265,9 +265,8 @@ func fetchCopyrightContents(resolver file.Resolver, dbLocation file.Location, m
|
||||
|
||||
reader, err := resolver.FileContentsByLocation(*location)
|
||||
if err != nil {
|
||||
log.Warnf("failed to fetch deb copyright contents (package=%s): %s", m.Package, err)
|
||||
log.Warnf("failed to fetch deb copyright contents (package=%s): %w", m.Package, err)
|
||||
}
|
||||
defer internal.CloseAndLogError(reader, location.RealPath)
|
||||
|
||||
l := location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package generic
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/go-logger"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
@@ -123,9 +122,17 @@ func (c *Cataloger) Catalog(ctx context.Context, resolver file.Resolver) ([]pkg.
|
||||
|
||||
log.WithFields("path", location.RealPath).Trace("parsing file contents")
|
||||
|
||||
discoveredPackages, discoveredRelationships, err := invokeParser(ctx, resolver, location, logger, parser, &env)
|
||||
contentReader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
continue // logging is handled within invokeParser
|
||||
logger.WithFields("location", location.RealPath, "error", err).Warn("unable to fetch contents")
|
||||
continue
|
||||
}
|
||||
|
||||
discoveredPackages, discoveredRelationships, err := parser(ctx, resolver, &env, file.NewLocationReadCloser(location, contentReader))
|
||||
internal.CloseAndLogError(contentReader, location.AccessPath)
|
||||
if err != nil {
|
||||
logger.WithFields("location", location.RealPath, "error", err).Warnf("cataloger failed")
|
||||
continue
|
||||
}
|
||||
|
||||
for _, p := range discoveredPackages {
|
||||
@@ -138,23 +145,6 @@ func (c *Cataloger) Catalog(ctx context.Context, resolver file.Resolver) ([]pkg.
|
||||
return packages, relationships, nil
|
||||
}
|
||||
|
||||
func invokeParser(ctx context.Context, resolver file.Resolver, location file.Location, logger logger.Logger, parser Parser, env *Environment) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
contentReader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
logger.WithFields("location", location.RealPath, "error", err).Warn("unable to fetch contents")
|
||||
return nil, nil, err
|
||||
}
|
||||
defer internal.CloseAndLogError(contentReader, location.AccessPath)
|
||||
|
||||
discoveredPackages, discoveredRelationships, err := parser(ctx, resolver, env, file.NewLocationReadCloser(location, contentReader))
|
||||
if err != nil {
|
||||
logger.WithFields("location", location.RealPath, "error", err).Warnf("cataloger failed")
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return discoveredPackages, discoveredRelationships, nil
|
||||
}
|
||||
|
||||
// selectFiles takes a set of file trees and resolves and file references of interest for future cataloging
|
||||
func (c *Cataloger) selectFiles(resolver file.Resolver) []request {
|
||||
var requests []request
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -87,103 +86,3 @@ func Test_Cataloger(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type spyReturningFileResolver struct {
|
||||
m *file.MockResolver
|
||||
s *spyingIoReadCloser
|
||||
}
|
||||
|
||||
type spyingIoReadCloser struct {
|
||||
rc io.ReadCloser
|
||||
closed bool
|
||||
}
|
||||
|
||||
func newSpyReturningFileResolver(s *spyingIoReadCloser, paths ...string) file.Resolver {
|
||||
m := file.NewMockResolverForPaths(paths...)
|
||||
return spyReturningFileResolver{
|
||||
m: m,
|
||||
s: s,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *spyingIoReadCloser) Read(p []byte) (n int, err error) {
|
||||
return s.Read(p)
|
||||
}
|
||||
|
||||
func (s *spyingIoReadCloser) Close() error {
|
||||
s.closed = true
|
||||
return s.rc.Close()
|
||||
}
|
||||
|
||||
var _ io.ReadCloser = (*spyingIoReadCloser)(nil)
|
||||
|
||||
func (m spyReturningFileResolver) FileContentsByLocation(location file.Location) (io.ReadCloser, error) {
|
||||
return m.s, nil
|
||||
}
|
||||
|
||||
func (m spyReturningFileResolver) HasPath(path string) bool {
|
||||
return m.m.HasPath(path)
|
||||
}
|
||||
|
||||
func (m spyReturningFileResolver) FilesByPath(paths ...string) ([]file.Location, error) {
|
||||
return m.m.FilesByPath(paths...)
|
||||
}
|
||||
|
||||
func (m spyReturningFileResolver) FilesByGlob(patterns ...string) ([]file.Location, error) {
|
||||
return m.m.FilesByGlob(patterns...)
|
||||
}
|
||||
|
||||
func (m spyReturningFileResolver) FilesByMIMEType(types ...string) ([]file.Location, error) {
|
||||
return m.m.FilesByMIMEType(types...)
|
||||
}
|
||||
|
||||
func (m spyReturningFileResolver) RelativeFileByPath(f file.Location, path string) *file.Location {
|
||||
return m.m.RelativeFileByPath(f, path)
|
||||
}
|
||||
|
||||
func (m spyReturningFileResolver) AllLocations(ctx context.Context) <-chan file.Location {
|
||||
return m.m.AllLocations(ctx)
|
||||
}
|
||||
|
||||
func (m spyReturningFileResolver) FileMetadataByLocation(location file.Location) (file.Metadata, error) {
|
||||
return m.m.FileMetadataByLocation(location)
|
||||
}
|
||||
|
||||
var _ file.Resolver = (*spyReturningFileResolver)(nil)
|
||||
|
||||
func TestClosesFileOnParserPanic(t *testing.T) {
|
||||
rc := io.NopCloser(strings.NewReader("some string"))
|
||||
spy := spyingIoReadCloser{
|
||||
rc: rc,
|
||||
}
|
||||
resolver := newSpyReturningFileResolver(&spy, "test-fixtures/another-path.txt")
|
||||
ctx := context.TODO()
|
||||
|
||||
processors := []processor{
|
||||
func(resolver file.Resolver, env Environment) []request {
|
||||
return []request{
|
||||
{
|
||||
Location: file.Location{
|
||||
LocationData: file.LocationData{
|
||||
Coordinates: file.Coordinates{},
|
||||
AccessPath: "/some/access/path",
|
||||
},
|
||||
},
|
||||
Parser: func(context.Context, file.Resolver, *Environment, file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
panic("panic!")
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
c := Cataloger{
|
||||
processor: processors,
|
||||
upstreamCataloger: "unit-test-cataloger",
|
||||
}
|
||||
|
||||
assert.PanicsWithValue(t, "panic!", func() {
|
||||
_, _, _ = c.Catalog(ctx, resolver)
|
||||
})
|
||||
require.True(t, spy.closed)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
@@ -66,7 +65,6 @@ func addFiles(resolver file.Resolver, dbLocation file.Location, p *pkg.Package)
|
||||
log.WithFields("path", dbLocation.RealPath).Warnf("failed to fetch portage contents (package=%s): %+v", p.Name, err)
|
||||
return
|
||||
}
|
||||
defer internal.CloseAndLogError(contentsReader, dbLocation.RealPath)
|
||||
|
||||
entry, ok := p.Metadata.(pkg.PortageEntry)
|
||||
if !ok {
|
||||
@@ -108,7 +106,6 @@ func addLicenses(resolver file.Resolver, dbLocation file.Location, p *pkg.Packag
|
||||
log.WithFields("path", dbLocation.RealPath).Warnf("failed to fetch portage LICENSE: %+v", err)
|
||||
return
|
||||
}
|
||||
defer internal.CloseAndLogError(licenseReader, location.RealPath)
|
||||
|
||||
findings := strset.New()
|
||||
scanner := bufio.NewScanner(licenseReader)
|
||||
@@ -144,7 +141,6 @@ func addSize(resolver file.Resolver, dbLocation file.Location, p *pkg.Package) {
|
||||
log.WithFields("name", p.Name).Warnf("failed to fetch portage SIZE: %+v", err)
|
||||
return
|
||||
}
|
||||
defer internal.CloseAndLogError(sizeReader, location.RealPath)
|
||||
|
||||
scanner := bufio.NewScanner(sizeReader)
|
||||
for scanner.Scan() {
|
||||
|
||||
@@ -2,7 +2,7 @@ package golang
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
@@ -75,11 +75,11 @@ func DefaultCatalogerConfig() CatalogerConfig {
|
||||
if err != nil {
|
||||
log.Debug("unable to determine user home dir: %v", err)
|
||||
} else {
|
||||
goPath = filepath.Join(homeDir, "go")
|
||||
goPath = path.Join(homeDir, "go")
|
||||
}
|
||||
}
|
||||
if goPath != "" {
|
||||
g.LocalModCacheDir = filepath.Join(goPath, "pkg", "mod")
|
||||
g.LocalModCacheDir = path.Join(goPath, "pkg", "mod")
|
||||
}
|
||||
}
|
||||
return g
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/go-git/go-git/v5/storage/memory"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
@@ -161,35 +160,24 @@ func (c *goLicenses) findLicenses(resolver file.Resolver, globMatch string) (out
|
||||
}
|
||||
|
||||
for _, l := range locations {
|
||||
parsed, err := c.parseLicenseFromLocation(l, resolver)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
fileName := path.Base(l.RealPath)
|
||||
if c.lowerLicenseFileNames.Has(strings.ToLower(fileName)) {
|
||||
contents, err := resolver.FileContentsByLocation(l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsed, err := licenses.Parse(contents, l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, parsed...)
|
||||
}
|
||||
out = append(out, parsed...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *goLicenses) parseLicenseFromLocation(l file.Location, resolver file.Resolver) ([]pkg.License, error) {
|
||||
var out []pkg.License
|
||||
fileName := path.Base(l.RealPath)
|
||||
if c.lowerLicenseFileNames.Has(strings.ToLower(fileName)) {
|
||||
contents, err := resolver.FileContentsByLocation(l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer internal.CloseAndLogError(contents, l.RealPath)
|
||||
parsed, err := licenses.Parse(contents, l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, parsed...)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func moduleDir(moduleName, moduleVersion string) string {
|
||||
return fmt.Sprintf("%s@%s", processCaps(moduleName), moduleVersion)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
@@ -120,7 +119,6 @@ func parseGoSumFile(resolver file.Resolver, reader file.LocationReadCloser) (map
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer internal.CloseAndLogError(contents, goSumLocation.AccessPath)
|
||||
|
||||
// go.sum has the format like:
|
||||
// github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
|
||||
@@ -344,17 +344,6 @@ var defaultCandidateAdditions = buildCandidateLookup(
|
||||
candidateKey{PkgName: "wpa_supplicant"},
|
||||
candidateAddition{AdditionalVendors: []string{"w1.fi"}},
|
||||
},
|
||||
{
|
||||
pkg.ApkPkg,
|
||||
candidateKey{PkgName: "dnsmasq", Vendor: "dnsmasq"},
|
||||
candidateAddition{AdditionalVendors: []string{"thekelleys"}},
|
||||
},
|
||||
// Debian packages
|
||||
{
|
||||
pkg.DebPkg,
|
||||
candidateKey{PkgName: "dnsmasq", Vendor: "dnsmasq"},
|
||||
candidateAddition{AdditionalVendors: []string{"thekelleys"}},
|
||||
},
|
||||
//
|
||||
// Binary packages
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,9 +52,11 @@ func generateIndexedDictionaryJSON(rawGzipData io.Reader) ([]byte, error) {
|
||||
func filterCpeList(cpeList CpeList) CpeList {
|
||||
var processedCpeList CpeList
|
||||
|
||||
seen := make(map[string]struct{})
|
||||
|
||||
for _, cpeItem := range cpeList.CpeItems {
|
||||
// Skip CPE items that don't have any references.
|
||||
if len(cpeItem.References.Reference) == 0 {
|
||||
if len(cpeItem.References) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -62,7 +64,6 @@ func filterCpeList(cpeList CpeList) CpeList {
|
||||
parsedName, err := wfn.Parse(cpeItem.Name)
|
||||
if err != nil {
|
||||
log.Printf("unable to parse CPE URI %q: %s", cpeItem.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if slices.Contains([]string{"h", "o"}, parsedName.Part) {
|
||||
@@ -70,17 +71,15 @@ func filterCpeList(cpeList CpeList) CpeList {
|
||||
}
|
||||
|
||||
normalizedName := normalizeCPE(parsedName).BindToURI()
|
||||
if _, ok := seen[normalizedName]; ok {
|
||||
continue
|
||||
}
|
||||
seen[normalizedName] = struct{}{}
|
||||
cpeItem.Name = normalizedName
|
||||
|
||||
cpeName := cpeItem.Cpe23Item.Name
|
||||
if cpeItem.Cpe23Item.Deprecation.DeprecatedBy.Name != "" {
|
||||
cpeName = cpeItem.Cpe23Item.Deprecation.DeprecatedBy.Name
|
||||
}
|
||||
|
||||
parsedCPE, err := wfn.Parse(cpeName)
|
||||
parsedCPE, err := wfn.Parse(cpeItem.Cpe23Item.Name)
|
||||
if err != nil {
|
||||
log.Printf("unable to parse CPE value %q: %s", cpeName, err)
|
||||
continue
|
||||
log.Printf("unable to parse CPE value %q: %s", cpeItem.Cpe23Item.Name, err)
|
||||
}
|
||||
|
||||
cpeItem.Cpe23Item.Name = normalizeCPE(parsedCPE).BindToFmtString()
|
||||
@@ -102,20 +101,13 @@ func normalizeCPE(cpe *wfn.Attributes) *wfn.Attributes {
|
||||
}
|
||||
|
||||
const (
|
||||
prefixForNPMPackages = "https://www.npmjs.com/package/"
|
||||
prefixForRubyGems = "https://rubygems.org/gems/"
|
||||
prefixForRubyGemsHTTP = "http://rubygems.org/gems/"
|
||||
prefixForNativeRubyGems = "https://github.com/ruby/"
|
||||
prefixForPyPIPackages = "https://pypi.org/project/"
|
||||
prefixForJenkinsPlugins = "https://plugins.jenkins.io/"
|
||||
prefixForJenkinsPluginsGitHub = "https://github.com/jenkinsci/"
|
||||
prefixForRustCrates = "https://crates.io/crates/"
|
||||
prefixForPHPPear = "https://pear.php.net/"
|
||||
prefixForPHPPearHTTP = "http://pear.php.net/"
|
||||
prefixForPHPPecl = "https://pecl.php.net/"
|
||||
prefixForPHPPeclHTTP = "http://pecl.php.net/"
|
||||
prefixForPHPComposer = "https://packagist.org/packages/"
|
||||
prefixForGoModules = "https://pkg.go.dev/"
|
||||
prefixForNPMPackages = "https://www.npmjs.com/package/"
|
||||
prefixForRubyGems = "https://rubygems.org/gems/"
|
||||
prefixForRubyGemsHTTP = "http://rubygems.org/gems/"
|
||||
prefixForNativeRubyGems = "https://github.com/ruby/"
|
||||
prefixForPyPIPackages = "https://pypi.org/project/"
|
||||
prefixForJenkinsPlugins = "https://github.com/jenkinsci/"
|
||||
prefixForRustCrates = "https://crates.io/crates/"
|
||||
)
|
||||
|
||||
// indexCPEList creates an index of CPEs by ecosystem.
|
||||
@@ -127,8 +119,8 @@ func indexCPEList(list CpeList) *dictionary.Indexed {
|
||||
for _, cpeItem := range list.CpeItems {
|
||||
cpeItemName := cpeItem.Cpe23Item.Name
|
||||
|
||||
for _, reference := range cpeItem.References.Reference {
|
||||
ref := reference.Href
|
||||
for _, reference := range cpeItem.References {
|
||||
ref := reference.Reference.Href
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(ref, prefixForNPMPackages):
|
||||
@@ -143,27 +135,12 @@ func indexCPEList(list CpeList) *dictionary.Indexed {
|
||||
case strings.HasPrefix(ref, prefixForPyPIPackages):
|
||||
addEntryForPyPIPackage(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForJenkinsPluginsGitHub):
|
||||
// It _might_ be a jenkins plugin!
|
||||
addEntryForJenkinsPluginGitHub(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForJenkinsPlugins):
|
||||
// It _might_ be a jenkins plugin!
|
||||
addEntryForJenkinsPlugin(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForRustCrates):
|
||||
addEntryForRustCrate(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForPHPPear), strings.HasPrefix(ref, prefixForPHPPearHTTP):
|
||||
addEntryForPHPPearPackage(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForPHPPecl), strings.HasPrefix(ref, prefixForPHPPeclHTTP):
|
||||
addEntryForPHPPeclPackage(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForPHPComposer):
|
||||
addEntryForPHPComposerPackage(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForGoModules):
|
||||
addEntryForGoModulePackage(indexed, ref, cpeItemName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,29 +148,21 @@ func indexCPEList(list CpeList) *dictionary.Indexed {
|
||||
return indexed
|
||||
}
|
||||
|
||||
func updateIndex(indexed *dictionary.Indexed, ecosystem string, pkgName string, cpe string) {
|
||||
if _, exists := indexed.EcosystemPackages[ecosystem]; !exists {
|
||||
indexed.EcosystemPackages[ecosystem] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
if indexed.EcosystemPackages[ecosystem][pkgName] == nil {
|
||||
indexed.EcosystemPackages[ecosystem][pkgName] = dictionary.NewSet()
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[ecosystem][pkgName].Add(cpe)
|
||||
}
|
||||
|
||||
func addEntryForRustCrate(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.TrimPrefix(ref, prefixForRustCrates)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemRustCrates, ref, cpeItemName)
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRustCrates]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRustCrates] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRustCrates][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForJenkinsPluginGitHub(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
func addEntryForJenkinsPlugin(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.TrimPrefix(ref, prefixForJenkinsPluginsGitHub)
|
||||
ref = strings.TrimPrefix(ref, prefixForJenkinsPlugins)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
if !strings.HasSuffix(ref, "-plugin") {
|
||||
@@ -202,19 +171,12 @@ func addEntryForJenkinsPluginGitHub(indexed *dictionary.Indexed, ref string, cpe
|
||||
}
|
||||
|
||||
ref = strings.TrimSuffix(ref, "-plugin")
|
||||
updateIndex(indexed, dictionary.EcosystemJenkinsPlugins, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForJenkinsPlugin(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.TrimPrefix(ref, prefixForJenkinsPlugins)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
if ref == "" {
|
||||
return
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemJenkinsPlugins, ref, cpeItemName)
|
||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForPyPIPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@@ -222,7 +184,11 @@ func addEntryForPyPIPackage(indexed *dictionary.Indexed, ref string, cpeItemName
|
||||
ref = strings.TrimPrefix(ref, prefixForPyPIPackages)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemPyPI, ref, cpeItemName)
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPyPI]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPyPI] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPyPI][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForNativeRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@@ -230,7 +196,11 @@ func addEntryForNativeRubyGem(indexed *dictionary.Indexed, ref string, cpeItemNa
|
||||
ref = strings.TrimPrefix(ref, prefixForNativeRubyGems)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemRubyGems, ref, cpeItemName)
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRubyGems]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@@ -239,7 +209,11 @@ func addEntryForRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName str
|
||||
ref = strings.TrimPrefix(ref, prefixForRubyGemsHTTP)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemRubyGems, ref, cpeItemName)
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRubyGems]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForNPMPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@@ -248,84 +222,9 @@ func addEntryForNPMPackage(indexed *dictionary.Indexed, ref string, cpeItemName
|
||||
ref = strings.Split(ref, "?")[0]
|
||||
ref = strings.TrimPrefix(ref, prefixForNPMPackages)
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemNPM, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func phpExtensionPackageFromURLFragment(ref string) string {
|
||||
if strings.HasPrefix(ref, "package/") { // package/HTML_QuickForm/download
|
||||
ref = strings.TrimPrefix(ref, "package/")
|
||||
components := strings.Split(ref, "/")
|
||||
|
||||
if len(components) < 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
ref = components[0]
|
||||
} else if strings.Contains(ref, "?package=") { // package-changelog.php?package=xhprof&release=0.9.4
|
||||
components := strings.Split(ref, "?package=")
|
||||
|
||||
if len(components) < 2 {
|
||||
return ""
|
||||
}
|
||||
|
||||
components = strings.Split(components[1], "&")
|
||||
if len(components) < 2 {
|
||||
return ""
|
||||
}
|
||||
|
||||
ref = components[0]
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemNPM]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemNPM] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
return ref
|
||||
}
|
||||
|
||||
func addEntryForPHPPearPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPPear)
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPPearHTTP)
|
||||
ref = phpExtensionPackageFromURLFragment(ref)
|
||||
|
||||
if ref == "" {
|
||||
return
|
||||
}
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemPHPPear, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForPHPPeclPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPPecl)
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPPeclHTTP)
|
||||
ref = phpExtensionPackageFromURLFragment(ref)
|
||||
|
||||
if ref == "" {
|
||||
return
|
||||
}
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemPHPPecl, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForPHPComposerPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPComposer)
|
||||
components := strings.Split(ref, "/")
|
||||
|
||||
if len(components) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
ref = components[0] + "/" + components[1]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemPHPComposer, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForGoModulePackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.Split(ref, "?")[0]
|
||||
ref = strings.TrimPrefix(ref, prefixForGoModules)
|
||||
|
||||
// Ignore the vulnerability reports endpoints
|
||||
if strings.HasPrefix(ref, "vuln/") {
|
||||
return
|
||||
}
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemGoModules, ref, cpeItemName)
|
||||
indexed.EcosystemPackages[dictionary.EcosystemNPM][ref] = cpeItemName
|
||||
}
|
||||
|
||||
+19
-111
@@ -8,7 +8,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -60,46 +59,33 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemRustCrates: {
|
||||
"unicycle": dictionary.NewSet("cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*"),
|
||||
"unicycle": "cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForJenkinsPluginGitHub",
|
||||
addEntryFunc: addEntryForJenkinsPluginGitHub,
|
||||
inputRef: "https://github.com/jenkinsci/sonarqube-plugin",
|
||||
inputCpeItemName: "cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemJenkinsPlugins: {
|
||||
"sonarqube": dictionary.NewSet("cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForJenkinsPluginGitHub: not actually a plugin",
|
||||
addEntryFunc: addEntryForJenkinsPluginGitHub,
|
||||
inputRef: "https://github.com/jenkinsci/jenkins",
|
||||
inputCpeItemName: "cpe:2.3:a:jenkins:jenkinsci:2.7:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForJenkinsPlugin",
|
||||
addEntryFunc: addEntryForJenkinsPlugin,
|
||||
inputRef: "https://plugins.jenkins.io/svn-partial-release-mgr/release",
|
||||
inputCpeItemName: "cpe:2.3:a:jenkins:subversion_partial_release_manager:1.0.1:*:*:*:*:jenkins:*:*",
|
||||
inputRef: "https://github.com/jenkinsci/sonarqube-plugin",
|
||||
inputCpeItemName: "cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemJenkinsPlugins: {
|
||||
"svn-partial-release-mgr": dictionary.NewSet("cpe:2.3:a:jenkins:subversion_partial_release_manager:1.0.1:*:*:*:*:jenkins:*:*"),
|
||||
"sonarqube": "cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForJenkinsPlugin: not actually a plugin",
|
||||
addEntryFunc: addEntryForJenkinsPlugin,
|
||||
inputRef: "https://github.com/jenkinsci/jenkins",
|
||||
inputCpeItemName: "cpe:2.3:a:jenkins:jenkinsci:2.7:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPyPIPackage",
|
||||
addEntryFunc: addEntryForPyPIPackage,
|
||||
@@ -108,7 +94,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPyPI: {
|
||||
"vault-cli": dictionary.NewSet("cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*"),
|
||||
"vault-cli": "cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -121,7 +107,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemRubyGems: {
|
||||
"openssl": dictionary.NewSet("cpe:2.3:a:ruby-lang:openssl:-:*:*:*:*:ruby:*:*"),
|
||||
"openssl": "cpe:2.3:a:ruby-lang:openssl:-:*:*:*:*:ruby:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -134,7 +120,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemRubyGems: {
|
||||
"actionview": dictionary.NewSet("cpe:2.3:a:action_view_project:action_view:*:*:*:*:*:ruby:*:*"),
|
||||
"actionview": "cpe:2.3:a:action_view_project:action_view:*:*:*:*:*:ruby:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -147,7 +133,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemRubyGems: {
|
||||
"rbovirt": dictionary.NewSet("cpe:2.3:a:amos_benari:rbovirt:*:*:*:*:*:ruby:*:*"),
|
||||
"rbovirt": "cpe:2.3:a:amos_benari:rbovirt:*:*:*:*:*:ruby:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -160,85 +146,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemNPM: {
|
||||
"@nubosoftware/node-static": dictionary.NewSet("cpe:2.3:a:\\@nubosoftware\\/node-static_project:\\@nubosoftware\\/node-static:-:*:*:*:*:node.js:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPPeclPackage",
|
||||
addEntryFunc: addEntryForPHPPeclPackage,
|
||||
inputRef: "https://pecl.php.net/package/imagick/something/something/v4007.0",
|
||||
inputCpeItemName: "cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPPecl: {
|
||||
"imagick": dictionary.NewSet("cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPPeclPackage http changelog",
|
||||
addEntryFunc: addEntryForPHPPeclPackage,
|
||||
inputRef: "http://pecl.php.net/package-changelog.php?package=memcached&release",
|
||||
inputCpeItemName: "cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPPecl: {
|
||||
"memcached": dictionary.NewSet("cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPPearPackage",
|
||||
addEntryFunc: addEntryForPHPPearPackage,
|
||||
inputRef: "https://pear.php.net/package/PEAR/download",
|
||||
inputCpeItemName: "cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPPear: {
|
||||
"PEAR": dictionary.NewSet("cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPPearPackage http changelog",
|
||||
addEntryFunc: addEntryForPHPPearPackage,
|
||||
inputRef: "http://pear.php.net/package-changelog.php?package=abcdefg&release",
|
||||
inputCpeItemName: "cpe:2.3:a:php:abcdefg:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPPear: {
|
||||
"abcdefg": dictionary.NewSet("cpe:2.3:a:php:abcdefg:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPComposerPackage",
|
||||
addEntryFunc: addEntryForPHPComposerPackage,
|
||||
inputRef: "https://packagist.org/packages/frappant/frp-form-answers",
|
||||
inputCpeItemName: "cpe:2.3:a:frappant:forms_export:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPComposer: {
|
||||
"frappant/frp-form-answers": dictionary.NewSet("cpe:2.3:a:frappant:forms_export:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForGoModulePackage",
|
||||
addEntryFunc: addEntryForGoModulePackage,
|
||||
inputRef: "https://pkg.go.dev/github.com/abc/123?whatever=xvgfhfhf",
|
||||
inputCpeItemName: "cpe:2.3:a:abc:123:*:*:*:*:*:go:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemGoModules: {
|
||||
"github.com/abc/123": dictionary.NewSet("cpe:2.3:a:abc:123:*:*:*:*:*:go:*:*"),
|
||||
"@nubosoftware/node-static": "cpe:2.3:a:\\@nubosoftware\\/node-static_project:\\@nubosoftware\\/node-static:-:*:*:*:*:node.js:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -253,7 +161,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
|
||||
tt.addEntryFunc(indexed, tt.inputRef, tt.inputCpeItemName)
|
||||
|
||||
if diff := cmp.Diff(tt.expectedIndexed, *indexed, cmp.AllowUnexported(strset.Set{})); diff != "" {
|
||||
if diff := cmp.Diff(tt.expectedIndexed, *indexed); diff != "" {
|
||||
t.Errorf("addEntry* mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user