Compare commits

..
Author SHA1 Message Date
Weston Steimel e4fc1af3b8 fix(java): improvements to maven groupid lookups
Signed-off-by: Weston Steimel <commits@weston.slmail.me>
2024-04-18 15:47:08 +01:00
123 changed files with 5011 additions and 16828 deletions
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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 }}
+4 -19
View File
@@ -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 = []
+4 -3
View File
@@ -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
+2 -2
View File
@@ -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/**/*
+5 -5
View File
@@ -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
+1 -1
View File
@@ -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:
+48
View File
@@ -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 }}
+6 -10
View File
@@ -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
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'anchore/syft' # only run for main repo
steps:
- uses: actions/checkout@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
+7 -7
View File
@@ -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
-8
View File
@@ -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".
+1 -1
View File
@@ -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
View File
@@ -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.
-10
View File
@@ -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
+21 -24
View File
@@ -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
+41 -42
View File
@@ -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=
+1 -1
View File
@@ -3,5 +3,5 @@ package internal
const (
// JSONSchemaVersion is the current schema version output by the JSON encoder
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
JSONSchemaVersion = "16.0.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 -14
View File
@@ -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...)
}
+5 -47
View File
@@ -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()
}
-98
View File
@@ -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")
})
})
}
}
+3 -3
View File
@@ -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)...)
}
+1 -2
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -13
View File
@@ -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
View File
@@ -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 {
+17 -25
View File
@@ -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{
-7
View File
@@ -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
}
-70
View File
@@ -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
@@ -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
View File
@@ -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{
-12
View File
@@ -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)
}
+19 -25
View File
@@ -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 {
-2
View File
@@ -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,
+2 -86
View File
@@ -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)
}
+158 -278
View File
@@ -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())
+2 -5
View File
@@ -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),
+32 -103
View File
@@ -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
}
+67 -110
View File
@@ -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,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
@@ -1,8 +0,0 @@
%NAME%
madeup
%VERSION%
20.30-4
%DEPENDS%
libtree-sitter.so
@@ -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
+7 -2
View File
@@ -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{
+2 -31
View File
@@ -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 {
@@ -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
```
+1 -1
View File
@@ -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)
}
+1 -2
View File
@@ -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)
+10 -20
View File
@@ -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() {
+3 -3
View File
@@ -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
+12 -24
View File
@@ -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&amp;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
}
@@ -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&amp;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&amp;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