mirror of
https://github.com/anchore/syft.git
synced 2026-10-13 06:37:22 +02:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78ad3d648f | ||
|
|
1b3e57c264 | ||
|
|
ad7edba2a5 | ||
|
|
e51d4bcda1 | ||
|
|
d8113b5f07 | ||
|
|
a35f64c971 |
+6
-6
@@ -2,7 +2,7 @@ tools:
|
||||
# we want to use a pinned version of binny to manage the toolchain (so binny manages itself!)
|
||||
- name: binny
|
||||
version:
|
||||
want: v0.7.0
|
||||
want: v0.6.3
|
||||
method: github-release
|
||||
with:
|
||||
repo: anchore/binny
|
||||
@@ -26,7 +26,7 @@ tools:
|
||||
# used for linting
|
||||
- name: golangci-lint
|
||||
version:
|
||||
want: v1.57.2
|
||||
want: v1.56.2
|
||||
method: github-release
|
||||
with:
|
||||
repo: golangci/golangci-lint
|
||||
@@ -42,7 +42,7 @@ tools:
|
||||
# used for signing the checksums file at release
|
||||
- name: cosign
|
||||
version:
|
||||
want: v2.2.4
|
||||
want: v2.2.3
|
||||
method: github-release
|
||||
with:
|
||||
repo: sigstore/cosign
|
||||
@@ -58,7 +58,7 @@ tools:
|
||||
# used to release all artifacts
|
||||
- name: goreleaser
|
||||
version:
|
||||
want: v1.25.1
|
||||
want: v1.24.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: goreleaser/goreleaser
|
||||
@@ -103,7 +103,7 @@ tools:
|
||||
# used for running all local and CI tasks
|
||||
- name: task
|
||||
version:
|
||||
want: v3.36.0
|
||||
want: v3.35.1
|
||||
method: github-release
|
||||
with:
|
||||
repo: go-task/task
|
||||
@@ -111,7 +111,7 @@ tools:
|
||||
# used for triggering a release
|
||||
- name: gh
|
||||
version:
|
||||
want: v2.48.0
|
||||
want: v2.45.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: cli/cli
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependencies"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependencies"
|
||||
open-pull-requests-limit: 10
|
||||
@@ -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 = []
|
||||
|
||||
@@ -17,13 +17,13 @@ jobs:
|
||||
# the job by event.
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- name: Restore base benchmark result
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: test/results/benchmark-main.txt
|
||||
# use base sha for PR or new commit hash for main push in benchmark result key
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
|
||||
echo "result=$OUTPUT" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
with:
|
||||
name: benchmark-test-results
|
||||
path: test/results/**/*
|
||||
|
||||
@@ -36,16 +36,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
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@d39d31e687223d841ef683f52467bd88e9b21c14 #v3.25.3
|
||||
uses: github/codeql-action/init@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 #v3.24.6
|
||||
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@d39d31e687223d841ef683f52467bd88e9b21c14 #v3.25.3
|
||||
uses: github/codeql-action/autobuild@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 #v3.24.6
|
||||
|
||||
# ℹ️ 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@d39d31e687223d841ef683f52467bd88e9b21c14 #v3.25.3
|
||||
uses: github/codeql-action/analyze@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 #v3.24.6
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- run: python .github/scripts/labeler.py
|
||||
env:
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
with:
|
||||
# we need to be able to get the commit for a tag
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
environment: release
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Check if tag already exists
|
||||
# note: this will fail if the tag already exists
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
git tag ${{ github.event.inputs.version }}
|
||||
|
||||
- name: Check static analysis results
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
|
||||
id: static-analysis
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check unit test results
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
|
||||
id: unit
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check integration test results
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
|
||||
id: integration
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check acceptance test results (linux)
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
|
||||
id: acceptance-linux
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check acceptance test results (mac)
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
|
||||
id: acceptance-mac
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check cli test results (linux)
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
uses: fountainhead/action-wait-for-check@297be350cf8393728ea4d4b39435c7d7ae167c93 # v1.1.0
|
||||
id: cli-linux
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
# required for goreleaser signs section with cosign
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -105,13 +105,13 @@ jobs:
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 #v3.1.0
|
||||
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d #v3.0.0
|
||||
with:
|
||||
username: ${{ secrets.ANCHOREOSSWRITE_DH_USERNAME }}
|
||||
password: ${{ secrets.ANCHOREOSSWRITE_DH_PAT }}
|
||||
username: ${{ secrets.TOOLBOX_DOCKER_USER }}
|
||||
password: ${{ secrets.TOOLBOX_DOCKER_PASS }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 #v3.1.0
|
||||
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d #v3.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -138,12 +138,12 @@ jobs:
|
||||
# for creating the release (requires write access to packages and content)
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# for updating brew formula in anchore/homebrew-syft
|
||||
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
|
||||
GITHUB_BREW_TOKEN: ${{ secrets.ANCHORE_GIT_READ_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@9fece9e20048ca9590af301449208b2b8861333b #v0.15.9
|
||||
continue-on-error: true
|
||||
with:
|
||||
artifact-name: sbom.spdx.json
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- 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@70a41aba780001da0a30141984ae2a0c95d8704e #v6.0.2
|
||||
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@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- 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@70a41aba780001da0a30141984ae2a0c95d8704e #v6.0.2
|
||||
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@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- 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@70a41aba780001da0a30141984ae2a0c95d8704e #v6.0.2
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
name: "Static analysis"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -31,49 +31,49 @@ jobs:
|
||||
name: "Unit tests"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- name: Restore file executable test-fixture cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: syft/file/cataloger/executable/test-fixtures/elf/bin
|
||||
key: ${{ runner.os }}-unit-file-executable-elf-cache-${{ hashFiles( 'syft/file/cataloger/executable/test-fixtures/elf/cache.fingerprint' ) }}
|
||||
|
||||
- name: Restore file executable shared-info test-fixture cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: syft/file/cataloger/executable/test-fixtures/shared-info/bin
|
||||
key: ${{ runner.os }}-unit-file-executable-shared-info-cache-${{ hashFiles( 'syft/file/cataloger/executable/test-fixtures/shared-info/cache.fingerprint' ) }}
|
||||
|
||||
- name: Restore Java test-fixture cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: syft/pkg/cataloger/java/test-fixtures/java-builds/packages
|
||||
key: ${{ runner.os }}-unit-java-cache-${{ hashFiles( 'syft/pkg/cataloger/java/test-fixtures/java-builds/cache.fingerprint' ) }}
|
||||
|
||||
- name: Restore RPM test-fixture cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: syft/pkg/cataloger/redhat/test-fixtures/rpms
|
||||
key: ${{ runner.os }}-unit-rpm-cache-${{ hashFiles( 'syft/pkg/cataloger/redhat/test-fixtures/rpms.fingerprint' ) }}
|
||||
|
||||
- name: Restore go binary test-fixture cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: syft/pkg/cataloger/golang/test-fixtures/archs/binaries
|
||||
key: ${{ runner.os }}-unit-go-binaries-cache-${{ hashFiles( 'syft/pkg/cataloger/golang/test-fixtures/archs/binaries.fingerprint' ) }}
|
||||
|
||||
- name: Restore binary cataloger test-fixture cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: syft/pkg/cataloger/binary/test-fixtures/classifiers/bin
|
||||
key: ${{ runner.os }}-unit-binary-cataloger-cache-${{ hashFiles( 'syft/pkg/cataloger/binary/test-fixtures/cache.fingerprint' ) }}
|
||||
|
||||
- name: Restore Kernel test-fixture cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: syft/pkg/cataloger/kernel/test-fixtures/cache
|
||||
key: ${{ runner.os }}-unit-kernel-cache-${{ hashFiles( 'syft/pkg/cataloger/kernel/test-fixtures/cache.fingerprint' ) }}
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
name: "Integration tests"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -96,7 +96,7 @@ jobs:
|
||||
run: make validate-cyclonedx-schema
|
||||
|
||||
- name: Restore integration test cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: ${{ github.workspace }}/cmd/syft/internal/test/integration/test-fixtures/cache
|
||||
key: ${{ runner.os }}-integration-test-cache-${{ hashFiles('/cmd/syft/internal/test/integration/test-fixtures/cache.fingerprint') }}
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
name: "Build snapshot artifacts"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -122,7 +122,7 @@ jobs:
|
||||
# why not use actions/upload-artifact? It is very slow (3 minutes to upload ~600MB of data, vs 10 seconds with this approach).
|
||||
# see https://github.com/actions/upload-artifact/issues/199 for more info
|
||||
- name: Upload snapshot artifacts
|
||||
uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache/save@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
# we need to preserve the snapshot data itself as well as the task data that confirms if the
|
||||
# snapshot build is stale or not. Otherwise the downstream jobs will attempt to rebuild the snapshot
|
||||
@@ -139,14 +139,14 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- name: Download snapshot build
|
||||
id: snapshot-cache
|
||||
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache/restore@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: |
|
||||
snapshot
|
||||
@@ -164,7 +164,7 @@ jobs:
|
||||
|
||||
- name: Restore install.sh test image cache
|
||||
id: install-test-image-cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: ${{ github.workspace }}/test/install/cache
|
||||
key: ${{ runner.os }}-install-test-image-cache-${{ hashFiles('test/install/cache.fingerprint') }}
|
||||
@@ -187,7 +187,7 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -199,7 +199,7 @@ jobs:
|
||||
|
||||
- name: Download snapshot build
|
||||
id: snapshot-cache
|
||||
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache/restore@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: |
|
||||
snapshot
|
||||
@@ -214,7 +214,7 @@ jobs:
|
||||
|
||||
- name: Restore docker image cache for compare testing
|
||||
id: mac-compare-testing-cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: image.tar
|
||||
key: ${{ runner.os }}-${{ hashFiles('test/compare/mac.sh') }}
|
||||
@@ -232,20 +232,20 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b #v4.1.4
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 #v4.1.2
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- name: Restore CLI test-fixture cache
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: ${{ github.workspace }}/test/cli/test-fixtures/cache
|
||||
key: ${{ runner.os }}-cli-test-cache-${{ hashFiles('test/cli/test-fixtures/cache.fingerprint') }}
|
||||
|
||||
- name: Download snapshot build
|
||||
id: snapshot-cache
|
||||
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 #v4.0.2
|
||||
uses: actions/cache/restore@ab5e6d0c87105b4c9c2047343972218f562e4319 #v4.0.1
|
||||
with:
|
||||
path: |
|
||||
snapshot
|
||||
|
||||
@@ -49,9 +49,6 @@ linters-settings:
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 40
|
||||
statements: 50
|
||||
gocritic:
|
||||
enabled-checks:
|
||||
- deferInLoop
|
||||
output:
|
||||
uniq-by-line: false
|
||||
run:
|
||||
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
<!-- Use this section to tell people about which versions of your project are
|
||||
currently being supported with security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 5.1.x | :white_check_mark: |
|
||||
| 5.0.x | :x: |
|
||||
| 4.0.x | :white_check_mark: |
|
||||
| < 4.0 | :x: |
|
||||
|
||||
-->
|
||||
|
||||
Security updates are applied only to the most recent release, try to always be up to date.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
<!-- Use this section to tell people how to report a vulnerability.
|
||||
|
||||
Tell them where to go, how often they can expect to get an update on a
|
||||
reported vulnerability, what to expect if the vulnerability is accepted or
|
||||
declined, etc. -->
|
||||
|
||||
To report a security issue, please email
|
||||
[security@anchore.com](mailto:security@anchore.com)
|
||||
with a description of the issue, the steps you took to create the issue,
|
||||
affected versions, and, if known, mitigations for the issue.
|
||||
|
||||
All support will be made on the best effort base, so please indicate the "urgency level" of the vulnerability as Critical, High, Medium or Low.
|
||||
+1
-1
@@ -390,7 +390,7 @@ tasks:
|
||||
|
||||
generate-cpe-dictionary-index:
|
||||
desc: Generate the CPE index based off of the latest available CPE dictionary
|
||||
dir: "syft/pkg/cataloger/internal/cpegenerate/dictionary"
|
||||
dir: "syft/pkg/cataloger/common/cpe/dictionary"
|
||||
cmds:
|
||||
- "go generate"
|
||||
|
||||
|
||||
@@ -249,6 +249,13 @@ func getSource(ctx context.Context, opts *options.Catalog, userInput string, sou
|
||||
return nil, fmt.Errorf("could not determine source: %w", err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if userInput == "power-user" {
|
||||
bus.Notify("Note: the 'power-user' command has been removed.")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to construct source from user input %q: %w", userInput, err)
|
||||
}
|
||||
|
||||
return src, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -460,12 +460,4 @@ var commonTestCases = []testCase{
|
||||
"Akismet Anti-spam: Spam Protection": "5.3",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find php pecl package",
|
||||
pkgType: pkg.PhpPeclPkg,
|
||||
pkgLanguage: pkg.PHP,
|
||||
pkgInfo: map[string]string{
|
||||
"memcached": "3.2.0",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
a:5:{s:4:"name";s:9:"memcached";s:4:"date";s:10:"2022-01-11";s:4:"time";s:8:"15:23:47";s:7:"version";a:2:{s:7:"release";s:5:"3.2.0";s:3:"api";s:5:"3.2.0";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}}
|
||||
@@ -16,37 +16,36 @@ require (
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240312213626-055233e539b4
|
||||
github.com/anchore/stereoscope v0.0.3-0.20240501181043-2e9894674185
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240202171727-877e1747d426
|
||||
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.1
|
||||
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.1+incompatible
|
||||
github.com/distribution/reference v0.5.0
|
||||
github.com/docker/docker v25.0.4+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.2
|
||||
github.com/go-git/go-billy/v5 v5.5.0
|
||||
github.com/go-git/go-git/v5 v5.12.0
|
||||
github.com/go-git/go-git/v5 v5.11.0
|
||||
github.com/go-test/deep v1.1.0
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/go-containerregistry v0.19.1
|
||||
github.com/google/go-containerregistry v0.19.0
|
||||
github.com/google/licensecheck v0.3.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gookit/color v1.5.4
|
||||
github.com/hashicorp/go-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.8
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.4
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
|
||||
github.com/knqyf263/go-rpmdb v0.1.0
|
||||
@@ -65,8 +64,8 @@ require (
|
||||
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/sergi/go-diff v1.3.1
|
||||
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
|
||||
@@ -77,10 +76,10 @@ require (
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1
|
||||
go.uber.org/goleak v1.3.0
|
||||
golang.org/x/mod v0.17.0
|
||||
golang.org/x/net v0.24.0
|
||||
golang.org/x/mod v0.16.0
|
||||
golang.org/x/net v0.22.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.29.8
|
||||
modernc.org/sqlite v1.29.3
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -92,7 +91,7 @@ require (
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.4 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.0.0 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
|
||||
github.com/adrg/xdg v0.4.0 // indirect
|
||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
@@ -103,6 +102,7 @@ require (
|
||||
github.com/charmbracelet/harmonica v0.2.0 // 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
|
||||
@@ -121,7 +121,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
|
||||
@@ -136,7 +135,7 @@ require (
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
@@ -155,17 +154,16 @@ require (
|
||||
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
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
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
|
||||
@@ -190,7 +188,7 @@ require (
|
||||
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/skeema/knownhosts v1.2.2 // indirect
|
||||
github.com/skeema/knownhosts v1.2.1 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
@@ -218,24 +216,24 @@ 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.22.0 // indirect
|
||||
golang.org/x/crypto v0.21.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.19.0 // indirect
|
||||
golang.org/x/term v0.19.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/term v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.19.0 // indirect
|
||||
golang.org/x/tools v0.17.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
||||
modernc.org/libc v1.49.3 // indirect
|
||||
modernc.org/libc v1.41.0 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/memory v1.7.2 // indirect
|
||||
modernc.org/strutil v1.2.0 // indirect
|
||||
modernc.org/token v1.1.0 // indirect
|
||||
)
|
||||
|
||||
@@ -77,8 +77,8 @@ github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5
|
||||
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
|
||||
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
||||
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||
github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
|
||||
@@ -109,10 +109,10 @@ github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0v
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZVsCYMrIZBpFxwV26CbsuoEh5muXD5I1Ods=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.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/packageurl-go v0.1.1-0.20240202171727-877e1747d426 h1:agoiZchSf1Nnnos1azwIg5hk5Ao9TzZNBD9++AChGEg=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240202171727-877e1747d426/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
|
||||
github.com/anchore/stereoscope v0.0.2-0.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.1 h1:xujcQeF73rh4jwu3+zhfQsvV18x+7zIjlw7/CYbzGJ0=
|
||||
github.com/charmbracelet/bubbletea v0.26.1/go.mod h1:FzKr7sKoO8iFVcdIBM9J0sJOcQv5nDQaYwsee3kpbgo=
|
||||
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=
|
||||
@@ -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=
|
||||
@@ -215,14 +217,14 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da h1:ZOjWpVsFZ06eIhnh4mkaceTiVoktdU67+M7KDHJ268M=
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v24.0.0+incompatible h1:0+1VshNwBQzQAx9lOl+OYCTCEAD8fKs/qeXMx3O0wqM=
|
||||
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.1+incompatible h1:oI+4kkAgIwwb54b9OC7Xc3hSgu1RlJA/Lln/DF72djQ=
|
||||
github.com/docker/docker v26.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v25.0.4+incompatible h1:XITZTrq+52tZyZxUOtFIahUf3aH367FLxJzt9vZeAF8=
|
||||
github.com/docker/docker v25.0.4+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=
|
||||
@@ -240,8 +242,6 @@ github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
|
||||
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elliotchance/phpserialize v1.4.0 h1:cAp/9+KSnEbUC8oYCE32n2n84BeW8HOY3HMDI8hG2OY=
|
||||
github.com/elliotchance/phpserialize v1.4.0/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lcLUAeS/AnGZ2e49TZs=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
@@ -255,8 +255,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,20 +281,20 @@ 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.2 h1:ay/6f7WHwRkOgpBec9DjMLRBAApziJommZ21NkOOCwY=
|
||||
github.com/gkampitakis/go-snaps v0.5.2/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=
|
||||
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
|
||||
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
|
||||
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -374,8 +372,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY=
|
||||
github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
|
||||
github.com/google/go-containerregistry v0.19.0 h1:uIsMRBV7m/HDkDxE/nXMnv1q+lOOSPlQ/ywc5JbB8Ic=
|
||||
github.com/google/go-containerregistry v0.19.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs=
|
||||
github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY=
|
||||
@@ -398,8 +396,8 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -473,8 +471,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.8 h1:8BCzJdSvUbaDuRba4YVh+SKMGcAAKdkcF3SVFbrHAtQ=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.8/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.4 h1:gOGo0613MoqUcf0xCj+h/V3sHDaZasfv152G6/5l91s=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.4/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg=
|
||||
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=
|
||||
@@ -536,8 +534,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 h1:P8UmIzZMYDR+NGImiFvErt6VWfIRPuGM+vyjiEdkmIw=
|
||||
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
@@ -571,8 +569,6 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
|
||||
@@ -590,8 +586,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=
|
||||
@@ -696,8 +692,8 @@ github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624
|
||||
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
@@ -708,14 +704,14 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
|
||||
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
|
||||
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
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=
|
||||
@@ -867,8 +863,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.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
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=
|
||||
@@ -909,8 +905,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -958,8 +954,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.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
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 +986,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 +1047,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 +1067,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.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.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.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
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=
|
||||
@@ -1156,8 +1151,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1315,8 +1310,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -1350,28 +1345,18 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
modernc.org/cc/v4 v4.20.0 h1:45Or8mQfbUqJOG9WaxvlFYOAQO0lQ5RvqBcFCXngjxk=
|
||||
modernc.org/cc/v4 v4.20.0/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||
modernc.org/ccgo/v4 v4.16.0 h1:ofwORa6vx2FMm0916/CkZjpFPSR70VwTjUCe2Eg5BnA=
|
||||
modernc.org/ccgo/v4 v4.16.0/go.mod h1:dkNyWIjFrVIZ68DTo36vHK+6/ShBn4ysU61So6PIqCI=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
||||
modernc.org/libc v1.49.3 h1:j2MRCRdwJI2ls/sGbeSk0t2bypOG/uvPZUsGQFDulqg=
|
||||
modernc.org/libc v1.49.3/go.mod h1:yMZuGkn7pXbKfoT/M35gFJOAEdSKdxL0q64sF7KqCDo=
|
||||
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
|
||||
modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||
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.8 h1:nGKglNx9K5v0As+zF0/Gcl1kMkmaU1XynYyq92PbsC8=
|
||||
modernc.org/sqlite v1.29.8/go.mod h1:lQPm27iqa4UNZpmr4Aor0MH0HkCLbt1huYDfWylLZFk=
|
||||
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
|
||||
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
|
||||
modernc.org/sqlite v1.29.3 h1:6L71d3zXVB8oubdVSuwiurNyYRetQ3It8l1FSwylwQ0=
|
||||
modernc.org/sqlite v1.29.3/go.mod h1:MjUIBKZ+tU/lqjNLbVAAMjsQPdWdA/ciwdhsT9kBwk8=
|
||||
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 +1364,4 @@ modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
||||
@@ -3,5 +3,5 @@ package internal
|
||||
const (
|
||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||
JSONSchemaVersion = "16.0.7"
|
||||
JSONSchemaVersion = "16.0.6"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
"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 file-to-file relationships for executables-to-executables
|
||||
// you need to make certain that they are unique, store in a map[id]map[id]relationship to avoid dupes.
|
||||
// before creating the new file-to-file relationship, check to see if there are packages that represent each
|
||||
// file. If there are, create a package-to-package, file-to-package, or package-to-file relationship as appropriate.
|
||||
|
||||
// 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 or package-to-file relationships that represent binary shared library dependencies
|
||||
// note: prefer package-to-package relationships over package-to-file relationships
|
||||
|
||||
relIndex := newRelationshipIndex()
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
// read all existing dependencyOf relationships
|
||||
for _, r := range s.Relationships {
|
||||
if r.Type != artifact.DependencyOfRelationship {
|
||||
continue
|
||||
}
|
||||
relIndex.track(r)
|
||||
}
|
||||
})
|
||||
|
||||
// find all new relationships to add...
|
||||
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
|
||||
}
|
||||
|
||||
for _, libReference := range exec.ImportedLibraries {
|
||||
// TODO: is this always a basename? technically no, it could be a path...
|
||||
libBasename := path.Base(libReference)
|
||||
|
||||
pkgsThatOwnLib := index.owningLibraryPackage(libBasename)
|
||||
if pkgsThatOwnLib == nil {
|
||||
// create package-to-file relationship...
|
||||
// if there is more than one library for this given library name, then we will include
|
||||
// all of them as dependencies since we don't know the LD_LIBRARY_PATH order
|
||||
// TODO: add configuration for LD_LIBRARY_PATH order?
|
||||
for _, libCoord := range index.owningLibraryLocations(libBasename).ToSlice() {
|
||||
relIndex.add(
|
||||
artifact.Relationship{
|
||||
From: libCoord,
|
||||
To: parentPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// don't create a package-to-package relationship for this library... since we can't
|
||||
continue
|
||||
}
|
||||
|
||||
// create a package-to-package relationship between the binary package and the library package
|
||||
// if there is more than one library for this given library name, then we will include
|
||||
// all of them as dependencies since we don't know the LD_LIBRARY_PATH order
|
||||
for _, pkgThatOwnsLib := range pkgsThatOwnLib.Sorted() {
|
||||
relIndex.add(
|
||||
artifact.Relationship{
|
||||
From: pkgThatOwnsLib,
|
||||
To: parentPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// so far this handles the first order dependencies from the binary package. Odds are that the OS package manager
|
||||
// will have already created a package-to-package relationship for the lib packages to other lib packages.
|
||||
|
||||
return relIndex.newRelationships()
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
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).
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
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) owningLibraryLocations(libraryBasename string) file.CoordinateSet {
|
||||
if set, ok := i.libLocationsByBasename[libraryBasename]; ok {
|
||||
return set
|
||||
}
|
||||
|
||||
return file.NewCoordinateSet()
|
||||
}
|
||||
|
||||
func (i *sharedLibraryIndex) owningLibraryPackage(libraryBasename string) *pkg.Collection {
|
||||
// find all packages that own a library by it's basename
|
||||
if set, ok := i.libLocationsByBasename[libraryBasename]; ok {
|
||||
for _, coord := range set.ToSlice() {
|
||||
if pkgSet, ok := i.packagesByLibraryPath[coord]; ok {
|
||||
return pkgSet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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) {
|
||||
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() {
|
||||
fileOwner, ok := p.Metadata.(pkg.FileOwner)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, pth := range fileOwner.OwnedFiles() {
|
||||
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,15 +1,20 @@
|
||||
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(builder sbomsync.Builder, cfg cataloging.RelationshipsConfig, src artifact.Identifiable) {
|
||||
func Finalize(resolver file.Resolver, builder sbomsync.Builder, cfg cataloging.RelationshipsConfig, src artifact.Identifiable) {
|
||||
accessor := builder.(sbomsync.Accessor)
|
||||
|
||||
// remove ELF packages that are already represented by a non-ELF package
|
||||
// TODO (also, how should we update the TUI to reflect that we removed packages?)
|
||||
|
||||
// add relationships showing packages that are evident by a file which is owned by another package (package-to-package)
|
||||
if cfg.PackageFileOwnershipOverlap {
|
||||
byFileOwnershipOverlapWorker(accessor)
|
||||
@@ -21,6 +26,12 @@ func Finalize(builder sbomsync.Builder, cfg cataloging.RelationshipsConfig, src
|
||||
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...)
|
||||
})
|
||||
|
||||
// add source "contains package" relationship (source-to-package)
|
||||
var sourceRelationships []artifact.Relationship
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
|
||||
@@ -111,10 +111,10 @@ func NewPackageTask(cfg CatalogingFactoryConfig, c pkg.Cataloger, tags ...string
|
||||
if cfg.DataGenerationConfig.GenerateCPEs {
|
||||
// generate CPEs (note: this is excluded from package ID, so is safe to mutate)
|
||||
// we might have binary classified CPE already with the package so we want to append here
|
||||
dictionaryCPEs, ok := cpe.DictionaryFind(p)
|
||||
dictionaryCPE, ok := cpe.DictionaryFind(p)
|
||||
if ok {
|
||||
log.Tracef("used CPE dictionary to find CPEs for %s package %q: %s", p.Type, p.Name, dictionaryCPEs)
|
||||
p.CPEs = append(p.CPEs, dictionaryCPEs...)
|
||||
log.Tracef("used CPE dictionary to find CPE for %s package %q: %s", p.Type, p.Name, dictionaryCPE.Attributes.BindToFmtString())
|
||||
p.CPEs = append(p.CPEs, dictionaryCPE)
|
||||
} else {
|
||||
p.CPEs = append(p.CPEs, cpe.Generate(p)...)
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
|
||||
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "javascript", "node", "npm",
|
||||
),
|
||||
newSimplePackageTaskFactory(php.NewComposerLockCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "php", "composer"),
|
||||
newSimplePackageTaskFactory(php.NewPeclCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, pkgcataloging.ImageTag, "php", "pecl"),
|
||||
newPackageTaskFactory(
|
||||
func(cfg CatalogingFactoryConfig) pkg.Cataloger {
|
||||
return python.NewPackageCataloger(cfg.PackagesConfig.Python)
|
||||
|
||||
@@ -22,8 +22,9 @@ func (s sourceIdentifierAdapter) ID() artifact.ID {
|
||||
}
|
||||
|
||||
func NewRelationshipsTask(cfg cataloging.RelationshipsConfig, src source.Description) Task {
|
||||
fn := func(_ context.Context, _ file.Resolver, builder sbomsync.Builder) error {
|
||||
fn := func(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
|
||||
relationship.Finalize(
|
||||
resolver,
|
||||
builder,
|
||||
cfg,
|
||||
&sourceIdentifierAdapter{desc: src})
|
||||
|
||||
+2318
-3213
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "anchore.io/schema/syft/json/16.0.7/document",
|
||||
"$id": "anchore.io/schema/syft/json/16.0.6/document",
|
||||
"$ref": "#/$defs/Document",
|
||||
"$defs": {
|
||||
"AlpmDbEntry": {
|
||||
@@ -1496,9 +1496,6 @@
|
||||
{
|
||||
"$ref": "#/$defs/PhpComposerLockEntry"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/PhpPeclEntry"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/PortageDbEntry"
|
||||
},
|
||||
@@ -1782,27 +1779,6 @@
|
||||
"dist"
|
||||
]
|
||||
},
|
||||
"PhpPeclEntry": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
"license": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"version"
|
||||
]
|
||||
},
|
||||
"PortageDbEntry": {
|
||||
"properties": {
|
||||
"installedSize": {
|
||||
|
||||
@@ -57,9 +57,6 @@ func machoHasEntrypoint(f *macho.File) bool {
|
||||
}
|
||||
|
||||
func machoHasExports(f *macho.File) bool {
|
||||
if f == nil || f.Symtab == nil {
|
||||
return false
|
||||
}
|
||||
for _, sym := range f.Symtab.Syms {
|
||||
// look for symbols that are:
|
||||
// - not private and are external
|
||||
|
||||
@@ -69,11 +69,6 @@ func Test_machoHasExports(t *testing.T) {
|
||||
fixture: "bin/hello_mac",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "gcc-amd64-darwin-exec-debug",
|
||||
fixture: "bin/gcc-amd64-darwin-exec-debug",
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
# invoke all make files in subdirectories
|
||||
.PHONY: all hello libhello
|
||||
|
||||
all: hello libhello ../bin/gcc-amd64-darwin-exec-debug
|
||||
all: hello libhello
|
||||
|
||||
hello:
|
||||
$(MAKE) -C hello
|
||||
|
||||
libhello:
|
||||
$(MAKE) -C libhello
|
||||
|
||||
../bin/gcc-amd64-darwin-exec-debug:
|
||||
curl -L -o ../bin/gcc-amd64-darwin-exec-debug https://github.com/golang/tools/raw/9ed98faabadd2cb94de86d5290b1c6942b7c4877/cmd/splitdwarf/internal/macho/testdata/gcc-amd64-darwin-exec-debug
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -36,8 +36,6 @@ func SourceInfo(p pkg.Package) string {
|
||||
answer = "acquired package info from rust cargo manifest"
|
||||
case pkg.PhpComposerPkg:
|
||||
answer = "acquired package info from PHP composer manifest"
|
||||
case pkg.PhpPeclPkg:
|
||||
answer = "acquired package info from PHP Pecl manifest"
|
||||
case pkg.CocoapodsPkg:
|
||||
answer = "acquired package info from installed cocoapods manifest file"
|
||||
case pkg.ConanPkg:
|
||||
|
||||
@@ -127,14 +127,6 @@ func Test_SourceInfo(t *testing.T) {
|
||||
"from PHP composer manifest",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.PhpPeclPkg,
|
||||
},
|
||||
expected: []string{
|
||||
"from PHP Pecl manifest",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.DartPubPkg,
|
||||
|
||||
@@ -3,8 +3,6 @@ package spdxjson
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -115,74 +113,6 @@ func TestSPDXJSONImageEncoder(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
func TestSPDX22JSONRequredProperties(t *testing.T) {
|
||||
cfg := DefaultEncoderConfig()
|
||||
cfg.Pretty = true
|
||||
cfg.Version = "2.2"
|
||||
|
||||
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
coords := file.Coordinates{
|
||||
RealPath: "/some/file",
|
||||
FileSystemID: "ac897d978b6c38749a1",
|
||||
}
|
||||
|
||||
p1 := pkg.Package{
|
||||
Name: "files-analyzed-true",
|
||||
Version: "v1",
|
||||
Locations: file.NewLocationSet(file.NewLocation(coords.RealPath)),
|
||||
Licenses: pkg.LicenseSet{},
|
||||
Language: pkg.Java,
|
||||
Metadata: pkg.JavaArchive{
|
||||
ArchiveDigests: []file.Digest{
|
||||
{
|
||||
Algorithm: "sha256",
|
||||
Value: "a9b87321a9879c79d87987987a97c97b9789ce978dffea987",
|
||||
},
|
||||
},
|
||||
Parent: nil,
|
||||
},
|
||||
}
|
||||
p1.SetID()
|
||||
|
||||
p2 := pkg.Package{
|
||||
Name: "files-analyzed-false",
|
||||
Version: "v2",
|
||||
}
|
||||
p2.SetID()
|
||||
|
||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||
testutil.EncoderSnapshotTestConfig{
|
||||
Subject: sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
Packages: pkg.NewCollection(p1, p2),
|
||||
FileDigests: map[file.Coordinates][]file.Digest{
|
||||
coords: {
|
||||
{
|
||||
Algorithm: "sha1",
|
||||
Value: "3b4ab96c371d913e2a88c269844b6c5fb5cbe761",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Relationships: []artifact.Relationship{
|
||||
{
|
||||
From: p1,
|
||||
To: coords,
|
||||
Type: artifact.ContainsRelationship,
|
||||
},
|
||||
},
|
||||
},
|
||||
Format: enc,
|
||||
UpdateSnapshot: *updateSnapshot,
|
||||
PersistRedactionsInSnapshot: true,
|
||||
IsJSON: true,
|
||||
Redactor: redactor(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestSPDXRelationshipOrder(t *testing.T) {
|
||||
testImage := "image-simple"
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-2.2",
|
||||
"dataLicense": "CC0-1.0",
|
||||
"SPDXID": "SPDXRef-DOCUMENT",
|
||||
"name": "unknown",
|
||||
"documentNamespace":"redacted",
|
||||
"creationInfo": {
|
||||
"licenseListVersion":"redacted",
|
||||
"creators": [
|
||||
"Organization: Anchore, Inc",
|
||||
"Tool: -"
|
||||
],
|
||||
"created":"redacted"
|
||||
},
|
||||
"packages": [
|
||||
{
|
||||
"SPDXID": "SPDXRef-Package-files-analyzed-false-7d37ba9d2f7c574b",
|
||||
"copyrightText": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": false,
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"name": "files-analyzed-false",
|
||||
"sourceInfo": "acquired package info from the following paths: ",
|
||||
"supplier": "NOASSERTION",
|
||||
"versionInfo": "v2"
|
||||
},
|
||||
{
|
||||
"name": "files-analyzed-true",
|
||||
"SPDXID": "SPDXRef-Package-files-analyzed-true-035066c2086b8bb4",
|
||||
"versionInfo": "v1",
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": true,
|
||||
"packageVerificationCode": {
|
||||
"packageVerificationCodeValue": "6fe0c471faaaa544e33cae0918eabcdc1c798d18"
|
||||
},
|
||||
"checksums": [
|
||||
{
|
||||
"algorithm": "SHA256",
|
||||
"checksumValue": "a9b87321a9879c79d87987987a97c97b9789ce978dffea987"
|
||||
}
|
||||
],
|
||||
"sourceInfo": "acquired package info from the following paths: /some/file",
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"copyrightText": "NOASSERTION"
|
||||
},
|
||||
{
|
||||
"SPDXID": "SPDXRef-DocumentRoot-Unknown-",
|
||||
"copyrightText": "",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": false,
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"name": "",
|
||||
"supplier": "NOASSERTION"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"fileName": "/some/file",
|
||||
"SPDXID": "SPDXRef-File-some-file-2c5bc344430decac",
|
||||
"checksums": [
|
||||
{
|
||||
"algorithm": "SHA1",
|
||||
"checksumValue": "3b4ab96c371d913e2a88c269844b6c5fb5cbe761"
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": "",
|
||||
"comment": "layerID: ac897d978b6c38749a1"
|
||||
}
|
||||
],
|
||||
"relationships": [
|
||||
{
|
||||
"spdxElementId": "SPDXRef-Package-files-analyzed-true-035066c2086b8bb4",
|
||||
"relatedSpdxElement": "SPDXRef-File-some-file-2c5bc344430decac",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DocumentRoot-Unknown-",
|
||||
"relatedSpdxElement": "SPDXRef-Package-files-analyzed-false-7d37ba9d2f7c574b",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DocumentRoot-Unknown-",
|
||||
"relatedSpdxElement": "SPDXRef-Package-files-analyzed-true-035066c2086b8bb4",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DOCUMENT",
|
||||
"relatedSpdxElement": "SPDXRef-DocumentRoot-Unknown-",
|
||||
"relationshipType": "DESCRIBES"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -67,8 +67,6 @@
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": false,
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"primaryPackagePurpose": "FILE"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -74,8 +74,6 @@
|
||||
"checksumValue": "2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceCategory": "PACKAGE-MANAGER",
|
||||
|
||||
@@ -74,8 +74,6 @@
|
||||
"checksumValue": "2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceCategory": "PACKAGE-MANAGER",
|
||||
@@ -100,9 +98,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -118,9 +113,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -136,9 +128,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -154,9 +143,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -172,9 +158,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
},
|
||||
{
|
||||
@@ -190,9 +173,6 @@
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
}
|
||||
],
|
||||
|
||||
@@ -16,8 +16,6 @@ PackageSupplier: NOASSERTION
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
PrimaryPackagePurpose: FILE
|
||||
FilesAnalyzed: false
|
||||
PackageLicenseConcluded: NOASSERTION
|
||||
PackageLicenseDeclared: NOASSERTION
|
||||
|
||||
##### Package: @at-sign
|
||||
|
||||
|
||||
@@ -15,42 +15,36 @@ SPDXID: SPDXRef-File-a1-f6-9c2f7510199b17f6
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /d1/f3
|
||||
SPDXID: SPDXRef-File-d1-f3-c6f5b29dca12661f
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /d2/f4
|
||||
SPDXID: SPDXRef-File-d2-f4-c641caa71518099f
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /f1
|
||||
SPDXID: SPDXRef-File-f1-5265a4dde3edbf7c
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /f2
|
||||
SPDXID: SPDXRef-File-f2-f9e49132a4b96ccd
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
FileName: /z1/f5
|
||||
SPDXID: SPDXRef-File-z1-f5-839d99ee67d9d174
|
||||
FileType: OTHER
|
||||
FileChecksum: SHA1: 0000000000000000000000000000000000000000
|
||||
LicenseConcluded: NOASSERTION
|
||||
LicenseInfoInFile: NOASSERTION
|
||||
|
||||
##### Package: user-image-input
|
||||
|
||||
@@ -62,8 +56,6 @@ PackageDownloadLocation: NOASSERTION
|
||||
PrimaryPackagePurpose: CONTAINER
|
||||
FilesAnalyzed: false
|
||||
PackageChecksum: SHA256: 2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368
|
||||
PackageLicenseConcluded: NOASSERTION
|
||||
PackageLicenseDeclared: NOASSERTION
|
||||
ExternalRef: PACKAGE-MANAGER purl pkg:oci/user-image-input@sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368?arch=
|
||||
|
||||
##### Package: package-2
|
||||
|
||||
-2
@@ -16,8 +16,6 @@ PackageSupplier: NOASSERTION
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
PrimaryPackagePurpose: FILE
|
||||
FilesAnalyzed: false
|
||||
PackageLicenseConcluded: NOASSERTION
|
||||
PackageLicenseDeclared: NOASSERTION
|
||||
|
||||
##### Package: package-2
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ PackageDownloadLocation: NOASSERTION
|
||||
PrimaryPackagePurpose: CONTAINER
|
||||
FilesAnalyzed: false
|
||||
PackageChecksum: SHA256: 2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368
|
||||
PackageLicenseConcluded: NOASSERTION
|
||||
PackageLicenseDeclared: NOASSERTION
|
||||
ExternalRef: PACKAGE-MANAGER purl pkg:oci/user-image-input@sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368?arch=
|
||||
|
||||
##### Package: package-2
|
||||
|
||||
+40
-8
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
@@ -22,16 +21,21 @@ func GetSource(ctx context.Context, userInput string, cfg *GetSourceConfig) (sou
|
||||
}
|
||||
|
||||
var errs []error
|
||||
var fileNotFoundProviders []string
|
||||
var fileNotfound error
|
||||
|
||||
// call each source provider until we find a valid source
|
||||
for _, p := range providers {
|
||||
src, err := p.Provide(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
fileNotFoundProviders = append(fileNotFoundProviders, p.Name())
|
||||
} else {
|
||||
errs = append(errs, fmt.Errorf("%s: %w", p.Name(), err))
|
||||
err = eachError(err, func(err error) error {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
fileNotfound = err
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if src != nil {
|
||||
@@ -48,8 +52,8 @@ func GetSource(ctx context.Context, userInput string, cfg *GetSourceConfig) (sou
|
||||
}
|
||||
}
|
||||
|
||||
if len(fileNotFoundProviders) > 0 {
|
||||
errs = append(errs, fmt.Errorf("additionally, the following providers failed with %w: %s", os.ErrNotExist, strings.Join(fileNotFoundProviders, ", ")))
|
||||
if fileNotfound != nil {
|
||||
errs = append([]error{fileNotfound}, errs...)
|
||||
}
|
||||
return nil, sourceError(userInput, errs...)
|
||||
}
|
||||
@@ -67,3 +71,31 @@ func sourceError(userInput string, errs ...error) error {
|
||||
}
|
||||
return fmt.Errorf("errors occurred attempting to resolve '%s':%s", userInput, errorTexts)
|
||||
}
|
||||
|
||||
func eachError(err error, fn func(error) error) error {
|
||||
out := fn(err)
|
||||
// unwrap singly wrapped errors
|
||||
if e, ok := err.(interface {
|
||||
Unwrap() error
|
||||
}); ok {
|
||||
wrapped := e.Unwrap()
|
||||
got := eachError(wrapped, fn)
|
||||
// return the outer error if received the same wrapped error
|
||||
if errors.Is(got, wrapped) {
|
||||
return err
|
||||
}
|
||||
return got
|
||||
}
|
||||
// unwrap errors from errors.Join
|
||||
if errs, ok := err.(interface {
|
||||
Unwrap() []error
|
||||
}); ok {
|
||||
for _, e := range errs.Unwrap() {
|
||||
e = eachError(e, fn)
|
||||
if e != nil {
|
||||
out = errors.Join(out, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ func AllTypes() []any {
|
||||
pkg.NpmPackageLockEntry{},
|
||||
pkg.PhpComposerInstalledEntry{},
|
||||
pkg.PhpComposerLockEntry{},
|
||||
pkg.PhpPeclEntry{},
|
||||
pkg.PortageEntry{},
|
||||
pkg.PythonPackage{},
|
||||
pkg.PythonPipfileLockEntry{},
|
||||
|
||||
@@ -91,7 +91,6 @@ var jsonTypes = makeJSONTypes(
|
||||
jsonNames(pkg.YarnLockEntry{}, "javascript-yarn-lock-entry", "YarnLockJsonMetadata"),
|
||||
jsonNames(pkg.PhpComposerLockEntry{}, "php-composer-lock-entry", "PhpComposerJsonMetadata"),
|
||||
jsonNamesWithoutLookup(pkg.PhpComposerInstalledEntry{}, "php-composer-installed-entry", "PhpComposerJsonMetadata"), // the legacy value is split into two types, where the other is preferred
|
||||
jsonNames(pkg.PhpPeclEntry{}, "php-pecl-entry", "PhpPeclMetadata"),
|
||||
jsonNames(pkg.PortageEntry{}, "portage-db-entry", "PortageMetadata"),
|
||||
jsonNames(pkg.PythonPackage{}, "python-package", "PythonPackageMetadata"),
|
||||
jsonNames(pkg.PythonPipfileLockEntry{}, "python-pipfile-lock-entry", "PythonPipfileLockMetadata"),
|
||||
|
||||
@@ -200,11 +200,6 @@ func TestReflectTypeFromJSONName_LegacyValues(t *testing.T) {
|
||||
input: "PythonRequirementsMetadata",
|
||||
expected: reflect.TypeOf(pkg.PythonRequirementsEntry{}),
|
||||
},
|
||||
{
|
||||
name: "map pkg.PhpPeclEntry struct type",
|
||||
input: "PhpPeclMetadata",
|
||||
expected: reflect.TypeOf(pkg.PhpPeclEntry{}),
|
||||
},
|
||||
{
|
||||
name: "map pkg.ErlangRebarLockEntry struct type",
|
||||
input: "RebarLockMetadataType",
|
||||
@@ -419,12 +414,6 @@ func Test_JSONName_JSONLegacyName(t *testing.T) {
|
||||
expectedJSONName: "php-composer-installed-entry",
|
||||
expectedLegacyName: "PhpComposerJsonMetadata", // note: maps to multiple entries (v11-12 breaking change)
|
||||
},
|
||||
{
|
||||
name: "PhpPeclMetadata",
|
||||
metadata: pkg.PhpPeclEntry{},
|
||||
expectedJSONName: "php-pecl-entry",
|
||||
expectedLegacyName: "PhpPeclMetadata",
|
||||
},
|
||||
{
|
||||
name: "PortageMetadata",
|
||||
metadata: pkg.PortageEntry{},
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func Test_PackageURL(t *testing.T) {
|
||||
ID: "alpine",
|
||||
VersionID: "3.4.6",
|
||||
},
|
||||
expected: "pkg:apk/alpine/g%2B%2B@v84?arch=am86&distro=alpine-3.4.6",
|
||||
expected: "pkg:apk/alpine/g++@v84?arch=am86&distro=alpine-3.4.6",
|
||||
},
|
||||
{
|
||||
metadata: parsedData{
|
||||
|
||||
@@ -153,27 +153,6 @@ func FileContentsVersionMatcher(pattern string) EvidenceMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
// matchExcluding tests the provided regular expressions against the file, and if matched, DOES NOT return
|
||||
// anything that the matcher would otherwise return
|
||||
func matchExcluding(matcher EvidenceMatcher, contentPatternsToExclude ...string) EvidenceMatcher {
|
||||
var nonMatchPatterns []*regexp.Regexp
|
||||
for _, p := range contentPatternsToExclude {
|
||||
nonMatchPatterns = append(nonMatchPatterns, regexp.MustCompile(p))
|
||||
}
|
||||
return func(resolver file.Resolver, classifier Classifier, location file.Location) ([]pkg.Package, error) {
|
||||
contents, err := getContents(resolver, location)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
|
||||
}
|
||||
for _, nonMatch := range nonMatchPatterns {
|
||||
if nonMatch.Match(contents) {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
return matcher(resolver, classifier, location)
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocognit
|
||||
func sharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher EvidenceMatcher) EvidenceMatcher {
|
||||
pat := regexp.MustCompile(sharedLibraryPattern)
|
||||
|
||||
@@ -608,10 +608,10 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
{
|
||||
logicalFixture: "java-jre-openjdk/1.8.0_352-b08/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "java/jre",
|
||||
Name: "java",
|
||||
Version: "1.8.0_352-b08",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/java/jre@1.8.0_352-b08",
|
||||
PURL: "pkg:generic/java@1.8.0_352-b08",
|
||||
Locations: locations("java"),
|
||||
Metadata: metadata("java-binary-openjdk", "java"),
|
||||
},
|
||||
@@ -619,56 +619,23 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
{
|
||||
logicalFixture: "java-jre-openjdk/11.0.17/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "java/jre",
|
||||
Name: "java",
|
||||
Version: "11.0.17+8-LTS",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/java/jre@11.0.17%2B8-LTS",
|
||||
PURL: "pkg:generic/java@11.0.17+8-LTS",
|
||||
Locations: locations("java"),
|
||||
Metadata: metadata("java-binary-openjdk", "java"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "java-jre-openjdk-eclipse/11.0.22/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "java/jre",
|
||||
Version: "11.0.22+7",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/java/jre@11.0.22%2B7",
|
||||
Locations: locations("java"),
|
||||
Metadata: metadata("java-binary-openjdk", "java"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "java-jre-openjdk-arm64-eclipse/11.0.22/linux-arm64",
|
||||
expected: pkg.Package{
|
||||
Name: "java/jre",
|
||||
Version: "11.0.22+7",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/java/jre@11.0.22%2B7",
|
||||
Locations: locations("java"),
|
||||
Metadata: metadata("java-binary-openjdk", "java"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "java-graal-openjdk/17.0.3+7-jvmci-22.1-b06/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "java/graalvm",
|
||||
Version: "17.0.3+7-jvmci-22.1-b06",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/java/graalvm@17.0.3%2B7-jvmci-22.1-b06",
|
||||
Locations: locations("java"),
|
||||
Metadata: metadata("java-binary-graalvm", "java"),
|
||||
},
|
||||
},
|
||||
{
|
||||
// TODO: find original binary...
|
||||
// note: cannot find the original binary, using a custom snippet based on the original snippet in the repo
|
||||
logicalFixture: "java-jre-oracle/19.0.1/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "java/jre",
|
||||
Name: "java",
|
||||
Version: "19.0.1+10-21",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/java/jre@19.0.1%2B10-21",
|
||||
PURL: "pkg:generic/java@19.0.1+10-21",
|
||||
Locations: locations("java"),
|
||||
Metadata: metadata("java-binary-oracle", "java"),
|
||||
},
|
||||
@@ -678,10 +645,10 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
// note: cannot find the original binary, using a custom snippet based on the original snippet in the repo
|
||||
logicalFixture: "java-jre-oracle/19.0.1/darwin",
|
||||
expected: pkg.Package{
|
||||
Name: "java/jre",
|
||||
Name: "java",
|
||||
Version: "19.0.1+10-21",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/java/jre@19.0.1%2B10-21",
|
||||
PURL: "pkg:generic/java@19.0.1+10-21",
|
||||
Locations: locations("java"),
|
||||
Metadata: metadata("java-binary-oracle", "java"),
|
||||
},
|
||||
@@ -689,25 +656,14 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
{
|
||||
logicalFixture: "java-jre-ibm/1.8.0_391/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "java/jre",
|
||||
Name: "java",
|
||||
Version: "1.8.0-foreman_2023_10_12_13_27-b00",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/java/jre@1.8.0-foreman_2023_10_12_13_27-b00",
|
||||
PURL: "pkg:generic/java@1.8.0-foreman_2023_10_12_13_27-b00",
|
||||
Locations: locations("java"),
|
||||
Metadata: metadata("java-binary-ibm", "java"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "java-jdk-openjdk/21.0.2+13-LTS/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "java/jdk",
|
||||
Version: "21.0.2+13-LTS",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/java/jdk@21.0.2%2B13-LTS",
|
||||
Locations: locations("jdb"),
|
||||
Metadata: metadata("java-binary-jdk", "java"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "rust-libstd/1.50.0/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
|
||||
@@ -87,21 +87,12 @@ func DefaultClassifiers() []Classifier {
|
||||
{
|
||||
Class: "java-binary-openjdk",
|
||||
FileGlob: "**/java",
|
||||
EvidenceMatcher: matchExcluding(
|
||||
evidenceMatchers(
|
||||
FileContentsVersionMatcher(
|
||||
// [NUL]openjdk[NUL]java[NUL]0.0[NUL]11.0.17+8-LTS[NUL]
|
||||
// [NUL]openjdk[NUL]java[NUL]1.8[NUL]1.8.0_352-b08[NUL]
|
||||
`(?m)\x00openjdk\x00java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>[0-9]+[^\x00]+)\x00`),
|
||||
FileContentsVersionMatcher(
|
||||
// arm64 versions: [NUL]0.0[NUL][NUL][NUL][NUL][NUL]11.0.22+7[NUL][NUL][NUL][NUL][NUL][NUL][NUL]openjdk[NUL]java[NUL]
|
||||
`(?m)\x00(?P<release>[0-9]+[.0-9]*)\x00+(?P<version>[0-9]+[^\x00]+)\x00+openjdk\x00java`),
|
||||
),
|
||||
// don't match graalvm
|
||||
"-jvmci-",
|
||||
),
|
||||
Package: "java/jre",
|
||||
PURL: mustPURL("pkg:generic/java/jre@version"),
|
||||
EvidenceMatcher: FileContentsVersionMatcher(
|
||||
// [NUL]openjdk[NUL]java[NUL]0.0[NUL]11.0.17+8-LTS[NUL]
|
||||
// [NUL]openjdk[NUL]java[NUL]1.8[NUL]1.8.0_352-b08[NUL]
|
||||
`(?m)\x00openjdk\x00java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>[0-9]+[^\x00]+)\x00`),
|
||||
Package: "java",
|
||||
PURL: mustPURL("pkg:generic/java@version"),
|
||||
// TODO the updates might need to be part of the CPE Attributes, like: 1.8.0:update152
|
||||
CPEs: singleCPE("cpe:2.3:a:oracle:openjdk:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
@@ -111,42 +102,20 @@ func DefaultClassifiers() []Classifier {
|
||||
EvidenceMatcher: FileContentsVersionMatcher(
|
||||
// [NUL]java[NUL]1.8[NUL][NUL][NUL][NUL]1.8.0-foreman_2022_09_22_15_30-b00[NUL]
|
||||
`(?m)\x00java\x00(?P<release>[0-9]+[.0-9]+)\x00{4}(?P<version>[0-9]+[-._a-zA-Z0-9]+)\x00`),
|
||||
Package: "java/jre",
|
||||
PURL: mustPURL("pkg:generic/java/jre@version"),
|
||||
Package: "java",
|
||||
PURL: mustPURL("pkg:generic/java@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:ibm:java:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "java-binary-oracle",
|
||||
FileGlob: "**/java",
|
||||
EvidenceMatcher: matchExcluding(
|
||||
FileContentsVersionMatcher(
|
||||
// [NUL]19.0.1+10-21[NUL]
|
||||
`(?m)\x00(?P<version>[0-9]+[.0-9]+[+][-0-9]+)\x00`),
|
||||
// don't match openjdk
|
||||
`\x00openjdk\x00`,
|
||||
),
|
||||
Package: "java/jre",
|
||||
PURL: mustPURL("pkg:generic/java/jre@version"),
|
||||
EvidenceMatcher: FileContentsVersionMatcher(
|
||||
// [NUL]19.0.1+10-21[NUL]
|
||||
`(?m)\x00(?P<version>[0-9]+[.0-9]+[+][-0-9]+)\x00`),
|
||||
Package: "java",
|
||||
PURL: mustPURL("pkg:generic/java@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:oracle:jre:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "java-binary-graalvm",
|
||||
FileGlob: "**/java",
|
||||
EvidenceMatcher: FileContentsVersionMatcher(
|
||||
`(?m)\x00(?P<version>[0-9]+[.0-9]+[.0-9]+\+[0-9]+-jvmci-[0-9]+[.0-9]+-b[0-9]+)\x00`),
|
||||
Package: "java/graalvm",
|
||||
PURL: mustPURL("pkg:generic/java/graalvm@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:oracle:graalvm:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "java-binary-jdk",
|
||||
FileGlob: "**/jdb",
|
||||
EvidenceMatcher: FileContentsVersionMatcher(
|
||||
`(?m)\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\+[0-9]+)?([-._a-zA-Z0-9]+)?)\x00`),
|
||||
Package: "java/jdk",
|
||||
PURL: mustPURL("pkg:generic/java/jdk@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:oracle:jdk:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "nodejs-binary",
|
||||
FileGlob: "**/node",
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/mimetype"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
@@ -58,13 +57,31 @@ func (c *elfPackageCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
||||
// first find all ELF binaries that have notes
|
||||
var notesByLocation = make(map[elfPackageKey][]elfBinaryPackageNotes)
|
||||
for _, location := range locations {
|
||||
notes, key, err := parseElfPackageNotes(resolver, location, c)
|
||||
reader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, fmt.Errorf("unable to get binary contents %q: %w", location.Path(), err)
|
||||
}
|
||||
|
||||
notes, err := c.parseElfNotes(file.LocationReadCloser{
|
||||
Location: location,
|
||||
ReadCloser: reader,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithFields("file", location.Path(), "error", err).Trace("unable to parse ELF notes")
|
||||
continue
|
||||
}
|
||||
|
||||
if notes == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
notes.Location = location
|
||||
key := elfPackageKey{
|
||||
Name: notes.Name,
|
||||
Version: notes.Version,
|
||||
PURL: notes.PURL,
|
||||
CPE: notes.CPE,
|
||||
}
|
||||
notesByLocation[key] = append(notesByLocation[key], *notes)
|
||||
}
|
||||
|
||||
@@ -88,37 +105,6 @@ func (c *elfPackageCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
func parseElfPackageNotes(resolver file.Resolver, location file.Location, c *elfPackageCataloger) (*elfBinaryPackageNotes, elfPackageKey, error) {
|
||||
reader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
return nil, elfPackageKey{}, fmt.Errorf("unable to get binary contents %q: %w", location.Path(), err)
|
||||
}
|
||||
defer internal.CloseAndLogError(reader, location.AccessPath)
|
||||
|
||||
notes, err := c.parseElfNotes(file.LocationReadCloser{
|
||||
Location: location,
|
||||
ReadCloser: reader,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.WithFields("file", location.Path(), "error", err).Trace("unable to parse ELF notes")
|
||||
return nil, elfPackageKey{}, nil
|
||||
}
|
||||
|
||||
if notes == nil {
|
||||
return nil, elfPackageKey{}, nil
|
||||
}
|
||||
|
||||
notes.Location = location
|
||||
key := elfPackageKey{
|
||||
Name: notes.Name,
|
||||
Version: notes.Version,
|
||||
PURL: notes.PURL,
|
||||
CPE: notes.CPE,
|
||||
}
|
||||
return notes, key, nil
|
||||
}
|
||||
|
||||
func (c *elfPackageCataloger) parseElfNotes(reader file.LocationReadCloser) (*elfBinaryPackageNotes, error) {
|
||||
metadata, err := getELFNotes(reader)
|
||||
if err != nil {
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -203,39 +203,6 @@ from-images:
|
||||
paths:
|
||||
- /usr/lib/jvm/java-11-amazon-corretto/bin/java
|
||||
|
||||
- name: java-jre-openjdk-eclipse
|
||||
version: 11.0.22
|
||||
images:
|
||||
- ref: eclipse-temurin:11.0.22_7-jre@sha256:137960b9ec016cddeb366b7137546d37207d0f284f9492c23abf16a9c171dd51
|
||||
platform: linux/amd64
|
||||
paths:
|
||||
- /opt/java/openjdk/bin/java
|
||||
|
||||
- name: java-jre-openjdk-arm64-eclipse
|
||||
version: 11.0.22
|
||||
images:
|
||||
- ref: eclipse-temurin:11.0.22_7-jre@sha256:9bb82e8801e12e5377222fde83b5c91d87dc16f76c89e9f8affa678208f56797
|
||||
platform: linux/arm64
|
||||
paths:
|
||||
- /opt/java/openjdk/bin/java
|
||||
|
||||
- name: java-graal-openjdk
|
||||
version: 17.0.3+7-jvmci-22.1-b06
|
||||
images:
|
||||
- ref: springci/graalvm-ce:java17-0.12.x@sha256:110bf78b81e4e29c9217b565f10a1f11bb2ec0486d7336c047d803428e09685d
|
||||
platform: linux/amd64
|
||||
paths:
|
||||
- /opt/java/bin/java
|
||||
|
||||
- name: java-jdk-openjdk
|
||||
version: 21.0.2+13-LTS
|
||||
images:
|
||||
- ref: eclipse-temurin:21.0.2_13-jdk-alpine@sha256:b5d37df8ee5bb964bb340acca83957f9a09291d07768fba1881f6bfc8048e4f5
|
||||
platform: linux/amd64
|
||||
paths:
|
||||
- opt/java/openjdk/bin/jdb
|
||||
|
||||
|
||||
# TODO: this is not the original binary used in the test fixture
|
||||
# - version: 5.12.5
|
||||
# images:
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
@@ -148,7 +147,7 @@ func copyBinariesFromDockerImages(config config.BinaryFromImage, destination str
|
||||
}
|
||||
|
||||
func copyBinariesFromDockerImage(config config.BinaryFromImage, destination string, image config.Image) (err error) {
|
||||
containerName := fmt.Sprintf("%s-%s-%s", config.Name(), strings.ReplaceAll(config.Version, "+", "-"), uuid.New().String())
|
||||
containerName := fmt.Sprintf("%s-%s-%s", config.Name(), config.Version, uuid.New().String())
|
||||
|
||||
cmd := exec.Command("docker", "create", "--name", containerName, image.Reference)
|
||||
if err = cmd.Run(); err != nil {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -69,16 +69,13 @@ func buildDotNetPackage(versionResources map[string]string, f file.LocationReadC
|
||||
}
|
||||
|
||||
metadata := pkg.DotnetPortableExecutableEntry{
|
||||
AssemblyVersion: versionResources["Assembly Version"],
|
||||
LegalCopyright: versionResources["LegalCopyright"],
|
||||
Comments: versionResources["Comments"],
|
||||
InternalName: versionResources["InternalName"],
|
||||
CompanyName: versionResources["CompanyName"],
|
||||
ProductName: versionResources["ProductName"],
|
||||
ProductVersion: versionResources["ProductVersion"],
|
||||
FileDescription: versionResources["FileDescription"],
|
||||
FileVersion: versionResources["FileVersion"],
|
||||
OriginalFilename: versionResources["OriginalFilename"],
|
||||
AssemblyVersion: versionResources["Assembly Version"],
|
||||
LegalCopyright: versionResources["LegalCopyright"],
|
||||
Comments: versionResources["Comments"],
|
||||
InternalName: versionResources["InternalName"],
|
||||
CompanyName: versionResources["CompanyName"],
|
||||
ProductName: versionResources["ProductName"],
|
||||
ProductVersion: versionResources["ProductVersion"],
|
||||
}
|
||||
|
||||
dnpkg = pkg.Package{
|
||||
@@ -218,7 +215,7 @@ func findName(versionResources map[string]string) string {
|
||||
}
|
||||
|
||||
for _, field := range nameFields {
|
||||
value := resolveValue(versionResources[field], versionResources, nil)
|
||||
value := spaceNormalize(versionResources[field])
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
@@ -228,40 +225,6 @@ func findName(versionResources map[string]string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func resolveValue(value string, collection map[string]string, visited map[string]bool) string {
|
||||
value = spaceNormalize(value)
|
||||
|
||||
if value == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if visited == nil {
|
||||
visited = make(map[string]bool)
|
||||
}
|
||||
|
||||
if visited[value] {
|
||||
return value
|
||||
}
|
||||
visited[value] = true
|
||||
|
||||
hasIndirect, nextKey := hasIndirectFieldPrefix(value)
|
||||
if !hasIndirect {
|
||||
return value
|
||||
}
|
||||
|
||||
return resolveValue(collection[nextKey], collection, visited)
|
||||
}
|
||||
|
||||
func hasIndirectFieldPrefix(value string) (bool, string) {
|
||||
for _, prefix := range []string{"f#", "p("} {
|
||||
cleanValue := strings.TrimPrefix(value, prefix)
|
||||
if cleanValue != value {
|
||||
return true, cleanValue
|
||||
}
|
||||
}
|
||||
return false, value
|
||||
}
|
||||
|
||||
// normalizes a string to a trimmed version with all contigous whitespace collapsed to a single space character
|
||||
func spaceNormalize(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
|
||||
@@ -346,126 +346,3 @@ func Test_spaceNormalize(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_resolveValue(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
value string
|
||||
collection map[string]string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "simple value",
|
||||
value: "value",
|
||||
collection: map[string]string{
|
||||
"key": "value",
|
||||
},
|
||||
want: "value",
|
||||
},
|
||||
{
|
||||
name: "simple value with spaces",
|
||||
value: " value ",
|
||||
collection: map[string]string{
|
||||
"key": "value",
|
||||
},
|
||||
want: "value",
|
||||
},
|
||||
{
|
||||
name: "indirect value - f#",
|
||||
value: "f#other",
|
||||
collection: map[string]string{
|
||||
"key": "f#other",
|
||||
"other": "value",
|
||||
},
|
||||
want: "value",
|
||||
},
|
||||
{
|
||||
name: "indirect value - p(",
|
||||
value: "f#other",
|
||||
collection: map[string]string{
|
||||
"key": "p(other",
|
||||
"other": "value",
|
||||
},
|
||||
want: "value",
|
||||
},
|
||||
{
|
||||
name: "indirect value with cycles",
|
||||
value: "f#other",
|
||||
collection: map[string]string{
|
||||
"key": "f#other",
|
||||
"other": "f#key",
|
||||
},
|
||||
want: "f#other", // this is NOT ideal, but there is no "good" answer here
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, resolveValue(tt.value, tt.collection, nil))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_findVersion(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
versionResources map[string]string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "prefer file version over product version (when both semver)",
|
||||
versionResources: map[string]string{
|
||||
"FileVersion": "1.2.3",
|
||||
"ProductVersion": "4.5.6",
|
||||
},
|
||||
want: "4.5.6",
|
||||
},
|
||||
{
|
||||
name: "prefer file version over product version (when both semver)",
|
||||
versionResources: map[string]string{
|
||||
"FileVersion": "1.2.3",
|
||||
"ProductVersion": "4.5.6.7",
|
||||
},
|
||||
want: "1.2.3",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, findVersion(tt.versionResources))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_keepGreaterSemanticVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
productVersion string
|
||||
fileVersion string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "product semver is greater",
|
||||
productVersion: "3.0.0",
|
||||
fileVersion: "2.0.0",
|
||||
want: "3.0.0",
|
||||
},
|
||||
{
|
||||
name: "file semver is greater",
|
||||
productVersion: "2.0.0",
|
||||
fileVersion: "3.0.0",
|
||||
want: "3.0.0",
|
||||
},
|
||||
{
|
||||
name: "semver preferred over non-semver",
|
||||
productVersion: "3.0.0.2",
|
||||
fileVersion: "3.0.0",
|
||||
want: "3.0.0",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, keepGreaterSemanticVersion(tt.productVersion, tt.fileVersion))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -151,10 +151,7 @@ func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *exten
|
||||
return main
|
||||
}
|
||||
|
||||
// this is checking for (.L)? because at least one binary seems to have \xA0L preceding the version string, but for some reason
|
||||
// this is unable to be matched by the regex here as \x00\xA0L;
|
||||
// the only thing that seems to work is to just look for version strings following both \x00 and \x00.L for now
|
||||
var semverPattern = regexp.MustCompile(`\x00(.L)?(?P<version>v?(\d+\.\d+\.\d+[-\w]*[+\w]*))\x00`)
|
||||
var semverPattern = regexp.MustCompile(`\x00(?P<version>v?(\d+\.\d+\.\d+[-\w]*[+\w]*))\x00`)
|
||||
|
||||
func (c *goBinaryCataloger) findMainModuleVersion(metadata *pkg.GolangBinaryBuildinfoEntry, gbs pkg.KeyValues, reader io.ReadSeekCloser) string {
|
||||
vcsVersion, hasVersion := gbs.Get("vcs.revision")
|
||||
@@ -182,8 +179,16 @@ func (c *goBinaryCataloger) findMainModuleVersion(metadata *pkg.GolangBinaryBuil
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Trace("unable to seek to start of go binary reader")
|
||||
} else {
|
||||
if v := extractVersionFromContents(reader); v != "" {
|
||||
return v
|
||||
contents, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Trace("unable to read from go binary reader")
|
||||
} else {
|
||||
matchMetadata := internal.MatchNamedCaptureGroups(semverPattern, string(contents))
|
||||
|
||||
version, ok := matchMetadata["version"]
|
||||
if ok {
|
||||
return version
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -205,21 +210,6 @@ func (c *goBinaryCataloger) findMainModuleVersion(metadata *pkg.GolangBinaryBuil
|
||||
return ""
|
||||
}
|
||||
|
||||
func extractVersionFromContents(reader io.Reader) string {
|
||||
contents, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Trace("unable to read from go binary reader")
|
||||
return ""
|
||||
}
|
||||
matchMetadata := internal.MatchNamedCaptureGroups(semverPattern, string(contents))
|
||||
|
||||
version, ok := matchMetadata["version"]
|
||||
if ok {
|
||||
return version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func extractVersionFromLDFlags(ldflags string) (majorVersion string, fullVersion string) {
|
||||
if ldflags == "" {
|
||||
return "", ""
|
||||
|
||||
@@ -2,8 +2,6 @@ package golang
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -869,7 +867,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Version: "v1.0.0-somethingelse+incompatible",
|
||||
PURL: "pkg:golang/github.com/anchore/syft@v1.0.0-somethingelse%2Bincompatible",
|
||||
PURL: "pkg:golang/github.com/anchore/syft@v1.0.0-somethingelse+incompatible",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocationFromCoordinates(
|
||||
file.Coordinates{
|
||||
@@ -1092,53 +1090,3 @@ func Test_extractVersionFromLDFlags(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_extractVersionFromContents(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
contents io.Reader
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "empty string on error",
|
||||
contents: &alwaysErrorReader{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "empty string on empty reader",
|
||||
contents: bytes.NewReader([]byte{}),
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "null-byte delimited semver",
|
||||
contents: strings.NewReader("\x001.2.3\x00"),
|
||||
want: "1.2.3",
|
||||
},
|
||||
{
|
||||
name: "null-byte delimited semver with v prefix",
|
||||
contents: strings.NewReader("\x00v1.2.3\x00"),
|
||||
want: "v1.2.3",
|
||||
},
|
||||
{
|
||||
// 01a0bfc8: 0e74 5a3b 0000 a04c 7631 2e39 2e35 0000 .tZ;...Lv1.9.5.. from nginx-ingress-controller
|
||||
// at /nginx-ingress-controller in registry.k8s.io/ingress-nginx/controller:v1.9.5
|
||||
// digest: sha256:b3aba22b1da80e7acfc52b115cae1d4c687172cbf2b742d5b502419c25ff340e
|
||||
// TODO: eventually use something for managing snippets, similar to what's used with binary classifier tests
|
||||
name: "null byte, then random byte, then L then semver",
|
||||
contents: strings.NewReader("\x0e\x74\x5a\x3b\x00\x00\xa0\x4cv1.9.5\x00\x00"),
|
||||
want: "v1.9.5",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := extractVersionFromContents(tt.contents)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type alwaysErrorReader struct{}
|
||||
|
||||
func (alwaysErrorReader) Read(_ []byte) (int, error) {
|
||||
return 0, errors.New("read from always error reader")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -362,12 +351,6 @@ var defaultCandidateAdditions = buildCandidateLookup(
|
||||
candidateKey{PkgName: "node"},
|
||||
candidateAddition{AdditionalProducts: []string{"nodejs", "node.js"}},
|
||||
},
|
||||
// Conan packages
|
||||
{
|
||||
pkg.ConanPkg,
|
||||
candidateKey{PkgName: "poco"},
|
||||
candidateAddition{AdditionalVendors: []string{"pocoproject"}},
|
||||
},
|
||||
})
|
||||
|
||||
var defaultCandidateRemovals = buildCandidateRemovalLookup(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,9 +52,11 @@ func generateIndexedDictionaryJSON(rawGzipData io.Reader) ([]byte, error) {
|
||||
func filterCpeList(cpeList CpeList) CpeList {
|
||||
var processedCpeList CpeList
|
||||
|
||||
seen := make(map[string]struct{})
|
||||
|
||||
for _, cpeItem := range cpeList.CpeItems {
|
||||
// Skip CPE items that don't have any references.
|
||||
if len(cpeItem.References.Reference) == 0 {
|
||||
if len(cpeItem.References) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -62,7 +64,6 @@ func filterCpeList(cpeList CpeList) CpeList {
|
||||
parsedName, err := wfn.Parse(cpeItem.Name)
|
||||
if err != nil {
|
||||
log.Printf("unable to parse CPE URI %q: %s", cpeItem.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if slices.Contains([]string{"h", "o"}, parsedName.Part) {
|
||||
@@ -70,17 +71,15 @@ func filterCpeList(cpeList CpeList) CpeList {
|
||||
}
|
||||
|
||||
normalizedName := normalizeCPE(parsedName).BindToURI()
|
||||
if _, ok := seen[normalizedName]; ok {
|
||||
continue
|
||||
}
|
||||
seen[normalizedName] = struct{}{}
|
||||
cpeItem.Name = normalizedName
|
||||
|
||||
cpeName := cpeItem.Cpe23Item.Name
|
||||
if cpeItem.Cpe23Item.Deprecation.DeprecatedBy.Name != "" {
|
||||
cpeName = cpeItem.Cpe23Item.Deprecation.DeprecatedBy.Name
|
||||
}
|
||||
|
||||
parsedCPE, err := wfn.Parse(cpeName)
|
||||
parsedCPE, err := wfn.Parse(cpeItem.Cpe23Item.Name)
|
||||
if err != nil {
|
||||
log.Printf("unable to parse CPE value %q: %s", cpeName, err)
|
||||
continue
|
||||
log.Printf("unable to parse CPE value %q: %s", cpeItem.Cpe23Item.Name, err)
|
||||
}
|
||||
|
||||
cpeItem.Cpe23Item.Name = normalizeCPE(parsedCPE).BindToFmtString()
|
||||
@@ -102,20 +101,13 @@ func normalizeCPE(cpe *wfn.Attributes) *wfn.Attributes {
|
||||
}
|
||||
|
||||
const (
|
||||
prefixForNPMPackages = "https://www.npmjs.com/package/"
|
||||
prefixForRubyGems = "https://rubygems.org/gems/"
|
||||
prefixForRubyGemsHTTP = "http://rubygems.org/gems/"
|
||||
prefixForNativeRubyGems = "https://github.com/ruby/"
|
||||
prefixForPyPIPackages = "https://pypi.org/project/"
|
||||
prefixForJenkinsPlugins = "https://plugins.jenkins.io/"
|
||||
prefixForJenkinsPluginsGitHub = "https://github.com/jenkinsci/"
|
||||
prefixForRustCrates = "https://crates.io/crates/"
|
||||
prefixForPHPPear = "https://pear.php.net/"
|
||||
prefixForPHPPearHTTP = "http://pear.php.net/"
|
||||
prefixForPHPPecl = "https://pecl.php.net/"
|
||||
prefixForPHPPeclHTTP = "http://pecl.php.net/"
|
||||
prefixForPHPComposer = "https://packagist.org/packages/"
|
||||
prefixForGoModules = "https://pkg.go.dev/"
|
||||
prefixForNPMPackages = "https://www.npmjs.com/package/"
|
||||
prefixForRubyGems = "https://rubygems.org/gems/"
|
||||
prefixForRubyGemsHTTP = "http://rubygems.org/gems/"
|
||||
prefixForNativeRubyGems = "https://github.com/ruby/"
|
||||
prefixForPyPIPackages = "https://pypi.org/project/"
|
||||
prefixForJenkinsPlugins = "https://github.com/jenkinsci/"
|
||||
prefixForRustCrates = "https://crates.io/crates/"
|
||||
)
|
||||
|
||||
// indexCPEList creates an index of CPEs by ecosystem.
|
||||
@@ -127,8 +119,8 @@ func indexCPEList(list CpeList) *dictionary.Indexed {
|
||||
for _, cpeItem := range list.CpeItems {
|
||||
cpeItemName := cpeItem.Cpe23Item.Name
|
||||
|
||||
for _, reference := range cpeItem.References.Reference {
|
||||
ref := reference.Href
|
||||
for _, reference := range cpeItem.References {
|
||||
ref := reference.Reference.Href
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(ref, prefixForNPMPackages):
|
||||
@@ -143,27 +135,12 @@ func indexCPEList(list CpeList) *dictionary.Indexed {
|
||||
case strings.HasPrefix(ref, prefixForPyPIPackages):
|
||||
addEntryForPyPIPackage(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForJenkinsPluginsGitHub):
|
||||
// It _might_ be a jenkins plugin!
|
||||
addEntryForJenkinsPluginGitHub(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForJenkinsPlugins):
|
||||
// It _might_ be a jenkins plugin!
|
||||
addEntryForJenkinsPlugin(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForRustCrates):
|
||||
addEntryForRustCrate(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForPHPPear), strings.HasPrefix(ref, prefixForPHPPearHTTP):
|
||||
addEntryForPHPPearPackage(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForPHPPecl), strings.HasPrefix(ref, prefixForPHPPeclHTTP):
|
||||
addEntryForPHPPeclPackage(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForPHPComposer):
|
||||
addEntryForPHPComposerPackage(indexed, ref, cpeItemName)
|
||||
|
||||
case strings.HasPrefix(ref, prefixForGoModules):
|
||||
addEntryForGoModulePackage(indexed, ref, cpeItemName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,29 +148,21 @@ func indexCPEList(list CpeList) *dictionary.Indexed {
|
||||
return indexed
|
||||
}
|
||||
|
||||
func updateIndex(indexed *dictionary.Indexed, ecosystem string, pkgName string, cpe string) {
|
||||
if _, exists := indexed.EcosystemPackages[ecosystem]; !exists {
|
||||
indexed.EcosystemPackages[ecosystem] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
if indexed.EcosystemPackages[ecosystem][pkgName] == nil {
|
||||
indexed.EcosystemPackages[ecosystem][pkgName] = dictionary.NewSet()
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[ecosystem][pkgName].Add(cpe)
|
||||
}
|
||||
|
||||
func addEntryForRustCrate(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.TrimPrefix(ref, prefixForRustCrates)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemRustCrates, ref, cpeItemName)
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRustCrates]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRustCrates] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRustCrates][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForJenkinsPluginGitHub(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
func addEntryForJenkinsPlugin(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.TrimPrefix(ref, prefixForJenkinsPluginsGitHub)
|
||||
ref = strings.TrimPrefix(ref, prefixForJenkinsPlugins)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
if !strings.HasSuffix(ref, "-plugin") {
|
||||
@@ -202,19 +171,12 @@ func addEntryForJenkinsPluginGitHub(indexed *dictionary.Indexed, ref string, cpe
|
||||
}
|
||||
|
||||
ref = strings.TrimSuffix(ref, "-plugin")
|
||||
updateIndex(indexed, dictionary.EcosystemJenkinsPlugins, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForJenkinsPlugin(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.TrimPrefix(ref, prefixForJenkinsPlugins)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
if ref == "" {
|
||||
return
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemJenkinsPlugins, ref, cpeItemName)
|
||||
indexed.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForPyPIPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@@ -222,7 +184,11 @@ func addEntryForPyPIPackage(indexed *dictionary.Indexed, ref string, cpeItemName
|
||||
ref = strings.TrimPrefix(ref, prefixForPyPIPackages)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemPyPI, ref, cpeItemName)
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemPyPI]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPyPI] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemPyPI][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForNativeRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@@ -230,7 +196,11 @@ func addEntryForNativeRubyGem(indexed *dictionary.Indexed, ref string, cpeItemNa
|
||||
ref = strings.TrimPrefix(ref, prefixForNativeRubyGems)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemRubyGems, ref, cpeItemName)
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRubyGems]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@@ -239,7 +209,11 @@ func addEntryForRubyGem(indexed *dictionary.Indexed, ref string, cpeItemName str
|
||||
ref = strings.TrimPrefix(ref, prefixForRubyGemsHTTP)
|
||||
ref = strings.Split(ref, "/")[0]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemRubyGems, ref, cpeItemName)
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemRubyGems]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
indexed.EcosystemPackages[dictionary.EcosystemRubyGems][ref] = cpeItemName
|
||||
}
|
||||
|
||||
func addEntryForNPMPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
@@ -248,84 +222,9 @@ func addEntryForNPMPackage(indexed *dictionary.Indexed, ref string, cpeItemName
|
||||
ref = strings.Split(ref, "?")[0]
|
||||
ref = strings.TrimPrefix(ref, prefixForNPMPackages)
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemNPM, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func phpExtensionPackageFromURLFragment(ref string) string {
|
||||
if strings.HasPrefix(ref, "package/") { // package/HTML_QuickForm/download
|
||||
ref = strings.TrimPrefix(ref, "package/")
|
||||
components := strings.Split(ref, "/")
|
||||
|
||||
if len(components) < 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
ref = components[0]
|
||||
} else if strings.Contains(ref, "?package=") { // package-changelog.php?package=xhprof&release=0.9.4
|
||||
components := strings.Split(ref, "?package=")
|
||||
|
||||
if len(components) < 2 {
|
||||
return ""
|
||||
}
|
||||
|
||||
components = strings.Split(components[1], "&")
|
||||
if len(components) < 2 {
|
||||
return ""
|
||||
}
|
||||
|
||||
ref = components[0]
|
||||
if _, ok := indexed.EcosystemPackages[dictionary.EcosystemNPM]; !ok {
|
||||
indexed.EcosystemPackages[dictionary.EcosystemNPM] = make(dictionary.Packages)
|
||||
}
|
||||
|
||||
return ref
|
||||
}
|
||||
|
||||
func addEntryForPHPPearPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPPear)
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPPearHTTP)
|
||||
ref = phpExtensionPackageFromURLFragment(ref)
|
||||
|
||||
if ref == "" {
|
||||
return
|
||||
}
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemPHPPear, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForPHPPeclPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPPecl)
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPPeclHTTP)
|
||||
ref = phpExtensionPackageFromURLFragment(ref)
|
||||
|
||||
if ref == "" {
|
||||
return
|
||||
}
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemPHPPecl, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForPHPComposerPackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.TrimPrefix(ref, prefixForPHPComposer)
|
||||
components := strings.Split(ref, "/")
|
||||
|
||||
if len(components) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
ref = components[0] + "/" + components[1]
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemPHPComposer, ref, cpeItemName)
|
||||
}
|
||||
|
||||
func addEntryForGoModulePackage(indexed *dictionary.Indexed, ref string, cpeItemName string) {
|
||||
// Prune off the non-package-name parts of the URL
|
||||
ref = strings.Split(ref, "?")[0]
|
||||
ref = strings.TrimPrefix(ref, prefixForGoModules)
|
||||
|
||||
// Ignore the vulnerability reports endpoints
|
||||
if strings.HasPrefix(ref, "vuln/") {
|
||||
return
|
||||
}
|
||||
|
||||
updateIndex(indexed, dictionary.EcosystemGoModules, ref, cpeItemName)
|
||||
indexed.EcosystemPackages[dictionary.EcosystemNPM][ref] = cpeItemName
|
||||
}
|
||||
|
||||
+19
-111
@@ -8,7 +8,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -60,46 +59,33 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemRustCrates: {
|
||||
"unicycle": dictionary.NewSet("cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*"),
|
||||
"unicycle": "cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForJenkinsPluginGitHub",
|
||||
addEntryFunc: addEntryForJenkinsPluginGitHub,
|
||||
inputRef: "https://github.com/jenkinsci/sonarqube-plugin",
|
||||
inputCpeItemName: "cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemJenkinsPlugins: {
|
||||
"sonarqube": dictionary.NewSet("cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForJenkinsPluginGitHub: not actually a plugin",
|
||||
addEntryFunc: addEntryForJenkinsPluginGitHub,
|
||||
inputRef: "https://github.com/jenkinsci/jenkins",
|
||||
inputCpeItemName: "cpe:2.3:a:jenkins:jenkinsci:2.7:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForJenkinsPlugin",
|
||||
addEntryFunc: addEntryForJenkinsPlugin,
|
||||
inputRef: "https://plugins.jenkins.io/svn-partial-release-mgr/release",
|
||||
inputCpeItemName: "cpe:2.3:a:jenkins:subversion_partial_release_manager:1.0.1:*:*:*:*:jenkins:*:*",
|
||||
inputRef: "https://github.com/jenkinsci/sonarqube-plugin",
|
||||
inputCpeItemName: "cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemJenkinsPlugins: {
|
||||
"svn-partial-release-mgr": dictionary.NewSet("cpe:2.3:a:jenkins:subversion_partial_release_manager:1.0.1:*:*:*:*:jenkins:*:*"),
|
||||
"sonarqube": "cpe:2.3:a:sonarsource:sonarqube_scanner:2.7:*:*:*:*:jenkins:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForJenkinsPlugin: not actually a plugin",
|
||||
addEntryFunc: addEntryForJenkinsPlugin,
|
||||
inputRef: "https://github.com/jenkinsci/jenkins",
|
||||
inputCpeItemName: "cpe:2.3:a:jenkins:jenkinsci:2.7:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPyPIPackage",
|
||||
addEntryFunc: addEntryForPyPIPackage,
|
||||
@@ -108,7 +94,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPyPI: {
|
||||
"vault-cli": dictionary.NewSet("cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*"),
|
||||
"vault-cli": "cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -121,7 +107,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemRubyGems: {
|
||||
"openssl": dictionary.NewSet("cpe:2.3:a:ruby-lang:openssl:-:*:*:*:*:ruby:*:*"),
|
||||
"openssl": "cpe:2.3:a:ruby-lang:openssl:-:*:*:*:*:ruby:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -134,7 +120,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemRubyGems: {
|
||||
"actionview": dictionary.NewSet("cpe:2.3:a:action_view_project:action_view:*:*:*:*:*:ruby:*:*"),
|
||||
"actionview": "cpe:2.3:a:action_view_project:action_view:*:*:*:*:*:ruby:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -147,7 +133,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemRubyGems: {
|
||||
"rbovirt": dictionary.NewSet("cpe:2.3:a:amos_benari:rbovirt:*:*:*:*:*:ruby:*:*"),
|
||||
"rbovirt": "cpe:2.3:a:amos_benari:rbovirt:*:*:*:*:*:ruby:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -160,85 +146,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemNPM: {
|
||||
"@nubosoftware/node-static": dictionary.NewSet("cpe:2.3:a:\\@nubosoftware\\/node-static_project:\\@nubosoftware\\/node-static:-:*:*:*:*:node.js:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPPeclPackage",
|
||||
addEntryFunc: addEntryForPHPPeclPackage,
|
||||
inputRef: "https://pecl.php.net/package/imagick/something/something/v4007.0",
|
||||
inputCpeItemName: "cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPPecl: {
|
||||
"imagick": dictionary.NewSet("cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPPeclPackage http changelog",
|
||||
addEntryFunc: addEntryForPHPPeclPackage,
|
||||
inputRef: "http://pecl.php.net/package-changelog.php?package=memcached&release",
|
||||
inputCpeItemName: "cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPPecl: {
|
||||
"memcached": dictionary.NewSet("cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPPearPackage",
|
||||
addEntryFunc: addEntryForPHPPearPackage,
|
||||
inputRef: "https://pear.php.net/package/PEAR/download",
|
||||
inputCpeItemName: "cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPPear: {
|
||||
"PEAR": dictionary.NewSet("cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPPearPackage http changelog",
|
||||
addEntryFunc: addEntryForPHPPearPackage,
|
||||
inputRef: "http://pear.php.net/package-changelog.php?package=abcdefg&release",
|
||||
inputCpeItemName: "cpe:2.3:a:php:abcdefg:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPPear: {
|
||||
"abcdefg": dictionary.NewSet("cpe:2.3:a:php:abcdefg:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForPHPComposerPackage",
|
||||
addEntryFunc: addEntryForPHPComposerPackage,
|
||||
inputRef: "https://packagist.org/packages/frappant/frp-form-answers",
|
||||
inputCpeItemName: "cpe:2.3:a:frappant:forms_export:*:*:*:*:*:*:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemPHPComposer: {
|
||||
"frappant/frp-form-answers": dictionary.NewSet("cpe:2.3:a:frappant:forms_export:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "addEntryForGoModulePackage",
|
||||
addEntryFunc: addEntryForGoModulePackage,
|
||||
inputRef: "https://pkg.go.dev/github.com/abc/123?whatever=xvgfhfhf",
|
||||
inputCpeItemName: "cpe:2.3:a:abc:123:*:*:*:*:*:go:*:*",
|
||||
expectedIndexed: dictionary.Indexed{
|
||||
EcosystemPackages: map[string]dictionary.Packages{
|
||||
dictionary.EcosystemGoModules: {
|
||||
"github.com/abc/123": dictionary.NewSet("cpe:2.3:a:abc:123:*:*:*:*:*:go:*:*"),
|
||||
"@nubosoftware/node-static": "cpe:2.3:a:\\@nubosoftware\\/node-static_project:\\@nubosoftware\\/node-static:-:*:*:*:*:node.js:*:*",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -253,7 +161,7 @@ func Test_addEntryFuncs(t *testing.T) {
|
||||
|
||||
tt.addEntryFunc(indexed, tt.inputRef, tt.inputCpeItemName)
|
||||
|
||||
if diff := cmp.Diff(tt.expectedIndexed, *indexed, cmp.AllowUnexported(strset.Set{})); diff != "" {
|
||||
if diff := cmp.Diff(tt.expectedIndexed, *indexed); diff != "" {
|
||||
t.Errorf("addEntry* mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -3,19 +3,14 @@ package main
|
||||
type CpeItem struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Title string `xml:"title"`
|
||||
References struct {
|
||||
Reference []struct {
|
||||
References []struct {
|
||||
Reference struct {
|
||||
Href string `xml:"href,attr"`
|
||||
Body string `xml:",chardata"`
|
||||
} `xml:"reference"`
|
||||
} `xml:"references"`
|
||||
Cpe23Item struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Deprecation struct {
|
||||
DeprecatedBy struct {
|
||||
Name string `xml:"name,attr"`
|
||||
} `xml:"deprecated-by"`
|
||||
} `xml:"deprecation"`
|
||||
Name string `xml:"name,attr"`
|
||||
} `xml:"cpe23-item"`
|
||||
}
|
||||
|
||||
|
||||
Vendored
+11
-99
@@ -1,111 +1,23 @@
|
||||
{
|
||||
"ecosystems": {
|
||||
"go_modules": {
|
||||
"aahframe.work": [
|
||||
"cpe:2.3:a:aahframework:aah:*:*:*:*:*:go:*:*"
|
||||
],
|
||||
"github.com/ecnepsnai/web": [
|
||||
"cpe:2.3:a:web_project:web:*:*:*:*:*:go:*:*"
|
||||
],
|
||||
"github.com/square/squalor": [
|
||||
"cpe:2.3:a:square:squalor:*:*:*:*:*:go:*:*"
|
||||
],
|
||||
"gopkg.in/yaml.v3": [
|
||||
"cpe:2.3:a:yaml_project:yaml:*:*:*:*:*:go:*:*"
|
||||
]
|
||||
},
|
||||
"jenkins_plugins": {
|
||||
"anchore-container-scanner": [
|
||||
"cpe:2.3:a:anchore:container_image_scanner:*:*:*:*:*:jenkins:*:*",
|
||||
"cpe:2.3:a:jenkins:anchore_container_image_scanner:*:*:*:*:*:jenkins:*:*"
|
||||
],
|
||||
"fireline": [
|
||||
"cpe:2.3:a:jenkins:360_fireline:*:*:*:*:*:jenkins:*:*"
|
||||
],
|
||||
"sonarqube": [
|
||||
"cpe:2.3:a:sonarsource:sonarqube_scanner:*:*:*:*:*:jenkins:*:*"
|
||||
],
|
||||
"svn-partial-release-mgr": [
|
||||
"cpe:2.3:a:jenkins:subversion_partial_release_manager:*:*:*:*:*:jenkins:*:*"
|
||||
]
|
||||
"sonarqube": "cpe:2.3:a:sonarsource:sonarqube_scanner:*:*:*:*:*:jenkins:*:*"
|
||||
},
|
||||
"npm": {
|
||||
"merge-recursive": [
|
||||
"cpe:2.3:a:umbraengineering:merge-recursive:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"ps": [
|
||||
"cpe:2.3:a:umbraengineering:ps:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"static-dev-server": [
|
||||
"cpe:2.3:a:static-dev-server_project:static-dev-server:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"umount": [
|
||||
"cpe:2.3:a:umount_project:umount:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"undefsafe": [
|
||||
"cpe:2.3:a:undefsafe_project:undefsafe:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"underscore": [
|
||||
"cpe:2.3:a:underscorejs:underscore:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"underscore-99xp": [
|
||||
"cpe:2.3:a:underscore-99xp_project:underscore-99xp:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"ungit": [
|
||||
"cpe:2.3:a:ungit_project:ungit:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"unicode": [
|
||||
"cpe:2.3:a:unicode_project:unicode:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"unicode-json": [
|
||||
"cpe:2.3:a:unicode:unicode-json:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"unicorn-list": [
|
||||
"cpe:2.3:a:unicorn-list_project:unicorn-list:*:*:*:*:*:node.js:*:*"
|
||||
]
|
||||
},
|
||||
"php_composer": {
|
||||
"frappant/frp-form-answers": [
|
||||
"cpe:2.3:a:frappant:forms_export:*:*:*:*:*:typo3:*:*"
|
||||
]
|
||||
},
|
||||
"php_pear": {
|
||||
"HTML_QuickForm": [
|
||||
"cpe:2.3:a:html_quickform_project:html_quickform:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
"PEAR": [
|
||||
"cpe:2.3:a:php:pear:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
"XML_RPC": [
|
||||
"cpe:2.3:a:php:xml_rpc:*:*:*:*:*:pear:*:*"
|
||||
]
|
||||
},
|
||||
"php_pecl": {
|
||||
"imagick": [
|
||||
"cpe:2.3:a:php:imagick:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
"memcached": [
|
||||
"cpe:2.3:a:php:memcached:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
"xhprof": [
|
||||
"cpe:2.3:a:php:xhprof:*:*:*:*:*:*:*:*"
|
||||
]
|
||||
},
|
||||
"pypi": {
|
||||
"vault-cli": [
|
||||
"cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*"
|
||||
]
|
||||
"merge-recursive": "cpe:2.3:a:umbraengineering:merge-recursive:*:*:*:*:*:node.js:*:*",
|
||||
"static-dev-server": "cpe:2.3:a:static-dev-server_project:static-dev-server:*:*:*:*:*:node.js:*:*",
|
||||
"umount": "cpe:2.3:a:umount_project:umount:*:*:*:*:*:node.js:*:*",
|
||||
"undefsafe": "cpe:2.3:a:undefsafe_project:undefsafe:*:*:*:*:*:node.js:*:*",
|
||||
"underscore": "cpe:2.3:a:underscorejs:underscore:*:*:*:*:*:node.js:*:*",
|
||||
"underscore-99xp": "cpe:2.3:a:underscore-99xp_project:underscore-99xp:*:*:*:*:*:node.js:*:*",
|
||||
"unicode": "cpe:2.3:a:unicode_project:unicode:*:*:*:*:*:node.js:*:*",
|
||||
"unicorn-list": "cpe:2.3:a:unicorn-list_project:unicorn-list:*:*:*:*:*:node.js:*:*"
|
||||
},
|
||||
"rubygems": {
|
||||
"openssl": [
|
||||
"cpe:2.3:a:ruby-lang:openssl:*:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:ruby-lang:openssl:*:*:*:*:*:ruby:*:*"
|
||||
]
|
||||
"openssl": "cpe:2.3:a:ruby-lang:openssl:*:*:*:*:*:*:*:*"
|
||||
},
|
||||
"rust_crates": {
|
||||
"unicycle": [
|
||||
"cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*"
|
||||
]
|
||||
"unicycle": "cpe:2.3:a:unicycle_project:unicycle:*:*:*:*:*:rust:*:*"
|
||||
}
|
||||
}
|
||||
}
|
||||
-222
@@ -24873,226 +24873,4 @@
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:zzzcms:zzzphp:2.1.0:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:xhprof:0.9.1">
|
||||
<title xml:lang="en-US">PHP XHProf 0.9.1</title>
|
||||
<references>
|
||||
<reference href="http://pecl.php.net/package-changelog.php?package=xhprof&release=0.9.4">product changelog</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:xhprof:0.9.1:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:xhprof:0.9.2">
|
||||
<title xml:lang="en-US">PHP XHProf 0.9.2</title>
|
||||
<references>
|
||||
<reference href="http://pecl.php.net/package-changelog.php?package=xhprof&release=0.9.4">product changelog</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:xhprof:0.9.2:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:xhprof:0.9.3">
|
||||
<title xml:lang="en-US">PHP XHProf 0.9.3</title>
|
||||
<references>
|
||||
<reference href="http://pecl.php.net/package-changelog.php?package=xhprof&release=0.9.4">product changelog</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:xhprof:0.9.3:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:memcached:0.1.0">
|
||||
<title xml:lang="en-US">PHP memecached 0.1.0</title>
|
||||
<references>
|
||||
<reference href="https://pecl.php.net/package-changelog.php?package=memcached&release">Change Log</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:memcached:0.1.0:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:memcached:0.1.2">
|
||||
<title xml:lang="en-US">PHP memecached 0.1.2</title>
|
||||
<references>
|
||||
<reference href="https://pecl.php.net/package-changelog.php?package=memcached&release">Change Log</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:memcached:0.1.2:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:memcached:0.1.3">
|
||||
<title xml:lang="en-US">PHP memecached 0.1.3</title>
|
||||
<references>
|
||||
<reference href="https://pecl.php.net/package-changelog.php?package=memcached&release">Change Log</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:memcached:0.1.3:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:imagick:3.3.0">
|
||||
<title xml:lang="en-US">PHP Imagick 3.3.0</title>
|
||||
<references>
|
||||
<reference href="http://pecl.php.net/package/imagick">Version</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:imagick:3.3.0:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:imagick:3.4.0:-">
|
||||
<title xml:lang="en-US">PHP Imagick 3.4.0</title>
|
||||
<references>
|
||||
<reference href="http://pecl.php.net/package/imagick">Version</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:imagick:3.4.0:-:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:xml_rpc:1.4.4::~~~pear~~">
|
||||
<title xml:lang="en-US">PHP XML_RPC 1.4.4 for Pear</title>
|
||||
<references>
|
||||
<reference href="https://pear.php.net/package/XML_RPC/download/">Version</reference>
|
||||
<reference href="https://pear.php.net/package/XML_RPC/">Product</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:xml_rpc:1.4.4:*:*:*:*:pear:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:xml_rpc:1.4.5::~~~pear~~">
|
||||
<title xml:lang="en-US">PHP XML_RPC 1.4.5 for Pear</title>
|
||||
<references>
|
||||
<reference href="https://pear.php.net/package/XML_RPC/download/">Version</reference>
|
||||
<reference href="https://pear.php.net/package/XML_RPC/">Product</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:xml_rpc:1.4.5:*:*:*:*:pear:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:xml_rpc:1.4.6::~~~pear~~">
|
||||
<title xml:lang="en-US">PHP XML_RPC 1.4.6 for Pear</title>
|
||||
<references>
|
||||
<reference href="https://pear.php.net/package/XML_RPC/download/">Version</reference>
|
||||
<reference href="https://pear.php.net/package/XML_RPC/">Product</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:xml_rpc:1.4.6:*:*:*:*:pear:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:pear:1.0:-">
|
||||
<title xml:lang="en-US">PHP PEAR 1.0</title>
|
||||
<references>
|
||||
<reference href="https://pear.php.net/package/PEAR/download/">Change Log</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:pear:1.0:-:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:php:pear:1.0:b1">
|
||||
<title xml:lang="en-US">PHP PEAR 1.0 Beta 1</title>
|
||||
<references>
|
||||
<reference href="https://pear.php.net/package/PEAR/download/">Change Log</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:php:pear:1.0:b1:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:html_quickform_project:html_quickform:2.0">
|
||||
<title xml:lang="en-US">HTML_QuickForm project HTML_QuickForm 2.0</title>
|
||||
<references>
|
||||
<reference href="http://pear.php.net/package/HTML_QuickForm/">Project</reference>
|
||||
<reference href="http://pear.php.net/package/HTML_QuickForm/download">Version</reference>
|
||||
<reference href="http://some-other-unrelated-reference">Test</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:html_quickform_project:html_quickform:2.0:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:html_quickform_project:html_quickform:2.1">
|
||||
<title xml:lang="en-US">HTML_QuickForm project HTML_QuickForm 2.1</title>
|
||||
<references>
|
||||
<reference href="http://pear.php.net/package/HTML_QuickForm/">Project</reference>
|
||||
<reference href="http://pear.php.net/package/HTML_QuickForm/download">Version</reference>
|
||||
<reference href="http://some-other-unrelated-reference">Test</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:html_quickform_project:html_quickform:2.1:*:*:*:*:*:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:frappant:forms_export:-::~~~typo3~~">
|
||||
<title xml:lang="en-US">!Frappant Forms Export for TYPO3</title>
|
||||
<references>
|
||||
<reference href="https://packagist.org/packages/frappant/frp-form-answers">Version</reference>
|
||||
<reference href="https://frappant.ch/">Vendor</reference>
|
||||
<reference href="https://extensions.typo3.org/extension/frp_form_answers">Product</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:frappant:forms_export:-:*:*:*:*:typo3:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:jenkins:_subversion_partial_release_manager:1.0.1::~~~jenkins~~" deprecated="true" deprecation_date="2020-06-04T11:50:37.430Z">
|
||||
<title xml:lang="en-US">Jenkins Subversion Partial Release Manager 1.0.1 for Jenkins</title>
|
||||
<references>
|
||||
<reference href="https://github.com/jenkinsci/svn-partial-release-mgr-plugin">Version</reference>
|
||||
<reference href="https://plugins.jenkins.io/svn-partial-release-mgr">Product</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:jenkins:_subversion_partial_release_manager:1.0.1:*:*:*:*:jenkins:*:*">
|
||||
<cpe-23:deprecation date="2020-06-04T07:50:37.430-04:00">
|
||||
<cpe-23:deprecated-by name="cpe:2.3:a:jenkins:subversion_partial_release_manager:1.0.1:*:*:*:*:jenkins:*:*" type="NAME_CORRECTION"/>
|
||||
</cpe-23:deprecation>
|
||||
</cpe-23:cpe23-item>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:jenkins:360_fireline:1.0::~~~jenkins~~">
|
||||
<title xml:lang="en-US">Jenkins 360 FireLine 1.0 for Jenkins</title>
|
||||
<references>
|
||||
<reference href="https://plugins.jenkins.io/fireline">Product</reference>
|
||||
<reference href="https://github.com/jenkinsci/fireline-plugin">Version</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:jenkins:360_fireline:1.0:*:*:*:*:jenkins:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:anchore:container_image_scanner:-::~~~jenkins~~">
|
||||
<title xml:lang="en-US">Anchore Container Image Scanner for Jenkins</title>
|
||||
<references>
|
||||
<reference href="https://jenkins.io/security/advisory/2018-07-30/#SECURITY-1039">Advisory</reference>
|
||||
<reference href="https://github.com/jenkinsci/anchore-container-scanner-plugin/releases">Version</reference>
|
||||
<reference href="https://plugins.jenkins.io/anchore-container-scanner">Product</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:anchore:container_image_scanner:-:*:*:*:*:jenkins:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:anchore:container_image_scanner:1.0.0::~~~jenkins~~">
|
||||
<title xml:lang="en-US">Anchore Container Image Scanner 1.0.0 for Jenkins</title>
|
||||
<references>
|
||||
<reference href="https://jenkins.io/security/advisory/2018-07-30/#SECURITY-1039">Advisory</reference>
|
||||
<reference href="https://github.com/jenkinsci/anchore-container-scanner-plugin/releases">Version</reference>
|
||||
<reference href="https://plugins.jenkins.io/anchore-container-scanner">Product</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:anchore:container_image_scanner:1.0.0:*:*:*:*:jenkins:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:jenkins:anchore_container_image_scanner:1.0.0::~~~jenkins~~">
|
||||
<title xml:lang="en-US">Jenkins Anchore Container Image Scanner 1.0.0 for Jenkins</title>
|
||||
<references>
|
||||
<reference href="https://plugins.jenkins.io/anchore-container-scanner">Product</reference>
|
||||
<reference href="https://github.com/jenkinsci/anchore-container-scanner-plugin">Version</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:jenkins:anchore_container_image_scanner:1.0.0:*:*:*:*:jenkins:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:jenkins:anchore_container_image_scanner:1.0.1::~~~jenkins~~">
|
||||
<title xml:lang="en-US">Jenkins Anchore Container Image Scanner 1.0.1 for Jenkins</title>
|
||||
<references>
|
||||
<reference href="https://plugins.jenkins.io/anchore-container-scanner">Product</reference>
|
||||
<reference href="https://github.com/jenkinsci/anchore-container-scanner-plugin">Version</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:jenkins:anchore_container_image_scanner:1.0.1:*:*:*:*:jenkins:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:square:squalor:-::~~~go~~">
|
||||
<title xml:lang="en-US">Square Squalor - for Go</title>
|
||||
<references>
|
||||
<reference href="https://github.com/square/squalor/commit/f6f0a47cc344711042eb0970cb423e6950ba3f93">Advisory</reference>
|
||||
<reference href="https://pkg.go.dev/github.com/square/squalor?tab=versions">Version</reference>
|
||||
<reference href="https://square.github.io/">Product</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:square:squalor:-:*:*:*:*:go:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:tar-utils_project:tar-utils:-::~~~go~~">
|
||||
<title xml:lang="en-US">Tar-utils Project Tar-utils - for Go</title>
|
||||
<references>
|
||||
<reference href="https://github.com/whyrusleeping/tar-utils">Project</reference>
|
||||
<reference href="https://pkg.go.dev/vuln/GO-2021-0106">Advisory</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:tar-utils_project:tar-utils:-:*:*:*:*:go:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:web_project:web:1.0.0::~~~go~~">
|
||||
<title xml:lang="en-US">Web Project Web 1.0.0 for Go</title>
|
||||
<references>
|
||||
<reference href="https://github.com/ecnepsnai/web/releases">Change Log</reference>
|
||||
<reference href="https://github.com/ecnepsnai/web">Product</reference>
|
||||
<reference href="https://pkg.go.dev/github.com/ecnepsnai/web">Project</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:web_project:web:1.0.0:*:*:*:*:go:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:aahframework:aah:-::~~~go~~">
|
||||
<title xml:lang="en-US">aah framework aah for Go</title>
|
||||
<references>
|
||||
<reference href="https://pkg.go.dev/aahframe.work">Product</reference>
|
||||
<reference href="https://pkg.go.dev/vuln/GO-2020-0033">Advisory</reference>
|
||||
<reference href="https://aahframework.org/">Vendor</reference>
|
||||
<reference href="https://github.com/go-aah/aah/releases">Change Log</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:aahframework:aah:-:*:*:*:*:go:*:*"/>
|
||||
</cpe-item>
|
||||
<cpe-item name="cpe:/a:yaml_project:yaml:2.3.0::~~~go~~">
|
||||
<title xml:lang="en-US">YAML Project YAML 2.3.0 for Go</title>
|
||||
<references>
|
||||
<reference href="https://pkg.go.dev/gopkg.in/yaml.v3">Project</reference>
|
||||
<reference href="https://github.com/go-yaml/yaml">Project</reference>
|
||||
<reference href="https://github.com/go-yaml/yaml/tags">Version</reference>
|
||||
</references>
|
||||
<cpe-23:cpe23-item name="cpe:2.3:a:yaml_project:yaml:2.3.0:*:*:*:*:go:*:*"/>
|
||||
</cpe-item>
|
||||
</cpe-list>
|
||||
</cpe-list>
|
||||
</cpe-list>
|
||||
|
||||
@@ -1,51 +1,15 @@
|
||||
package dictionary
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
)
|
||||
|
||||
const (
|
||||
EcosystemNPM = "npm"
|
||||
EcosystemRubyGems = "rubygems"
|
||||
EcosystemPyPI = "pypi"
|
||||
EcosystemPHPPear = "php_pear"
|
||||
EcosystemPHPPecl = "php_pecl"
|
||||
EcosystemPHPComposer = "php_composer"
|
||||
EcosystemJenkinsPlugins = "jenkins_plugins"
|
||||
EcosystemRustCrates = "rust_crates"
|
||||
EcosystemGoModules = "go_modules"
|
||||
)
|
||||
|
||||
type Indexed struct {
|
||||
EcosystemPackages map[string]Packages `json:"ecosystems"`
|
||||
}
|
||||
|
||||
type Set struct {
|
||||
*strset.Set
|
||||
}
|
||||
|
||||
type Packages map[string]*Set
|
||||
|
||||
func NewSet(ts ...string) *Set {
|
||||
return &Set{strset.New(ts...)}
|
||||
}
|
||||
|
||||
func (s *Set) MarshalJSON() ([]byte, error) {
|
||||
l := s.List()
|
||||
slices.Sort(l)
|
||||
return json.Marshal(l)
|
||||
}
|
||||
|
||||
func (s *Set) UnmarshalJSON(data []byte) error {
|
||||
var strSlice []string
|
||||
|
||||
if err := json.Unmarshal(data, &strSlice); err == nil {
|
||||
*s = *NewSet(strSlice...)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
type Packages map[string]string
|
||||
|
||||
@@ -58,69 +58,52 @@ func GetIndexedDictionary() (_ *dictionary.Indexed, err error) {
|
||||
return indexedCPEDictionary, err
|
||||
}
|
||||
|
||||
func FromDictionaryFind(p pkg.Package) ([]cpe.CPE, bool) {
|
||||
func FromDictionaryFind(p pkg.Package) (cpe.CPE, bool) {
|
||||
dict, err := GetIndexedDictionary()
|
||||
parsedCPEs := []cpe.CPE{}
|
||||
if err != nil {
|
||||
log.Debugf("CPE dictionary lookup not available: %+v", err)
|
||||
return parsedCPEs, false
|
||||
return cpe.CPE{}, false
|
||||
}
|
||||
|
||||
var (
|
||||
cpes *dictionary.Set
|
||||
ok bool
|
||||
cpeString string
|
||||
ok bool
|
||||
)
|
||||
|
||||
switch p.Type {
|
||||
case pkg.NpmPkg:
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemNPM][p.Name]
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemNPM][p.Name]
|
||||
|
||||
case pkg.GemPkg:
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemRubyGems][p.Name]
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemRubyGems][p.Name]
|
||||
|
||||
case pkg.PythonPkg:
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemPyPI][p.Name]
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemPyPI][p.Name]
|
||||
|
||||
case pkg.JenkinsPluginPkg:
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][p.Name]
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemJenkinsPlugins][p.Name]
|
||||
|
||||
case pkg.RustPkg:
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemRustCrates][p.Name]
|
||||
|
||||
case pkg.PhpComposerPkg:
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemPHPComposer][p.Name]
|
||||
|
||||
case pkg.PhpPeclPkg:
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemPHPPecl][p.Name]
|
||||
|
||||
case pkg.GoModulePkg:
|
||||
cpes, ok = dict.EcosystemPackages[dictionary.EcosystemGoModules][p.Name]
|
||||
cpeString, ok = dict.EcosystemPackages[dictionary.EcosystemRustCrates][p.Name]
|
||||
|
||||
default:
|
||||
// The dictionary doesn't support this package type yet.
|
||||
return parsedCPEs, false
|
||||
return cpe.CPE{}, false
|
||||
}
|
||||
|
||||
if !ok {
|
||||
// The dictionary doesn't have a CPE for this package.
|
||||
return parsedCPEs, false
|
||||
return cpe.CPE{}, false
|
||||
}
|
||||
|
||||
for _, c := range cpes.List() {
|
||||
parsedCPE, err := cpe.New(c, cpe.NVDDictionaryLookupSource)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
parsedCPE.Attributes.Version = p.Version
|
||||
parsedCPEs = append(parsedCPEs, parsedCPE)
|
||||
parsedCPE, err := cpe.New(cpeString, cpe.NVDDictionaryLookupSource)
|
||||
if err != nil {
|
||||
return cpe.CPE{}, false
|
||||
}
|
||||
|
||||
if len(parsedCPEs) == 0 {
|
||||
return []cpe.CPE{}, false
|
||||
}
|
||||
parsedCPE.Attributes.Version = p.Version
|
||||
|
||||
return parsedCPEs, true
|
||||
return parsedCPE, true
|
||||
}
|
||||
|
||||
// FromPackageAttributes Create a list of CPEs for a given package, trying to guess the vendor, product tuple. We should be trying to
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
@@ -992,7 +991,7 @@ func TestDictionaryFindIsWired(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pkg pkg.Package
|
||||
want []cpe.CPE
|
||||
want string
|
||||
wantExists bool
|
||||
}{
|
||||
{
|
||||
@@ -1002,10 +1001,7 @@ func TestDictionaryFindIsWired(t *testing.T) {
|
||||
Version: "1.0.2k",
|
||||
Type: pkg.GemPkg,
|
||||
},
|
||||
want: []cpe.CPE{
|
||||
cpe.Must("cpe:2.3:a:ruby-lang:openssl:1.0.2k:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
|
||||
cpe.Must("cpe:2.3:a:ruby-lang:openssl:1.0.2k:*:*:*:*:ruby:*:*", cpe.NVDDictionaryLookupSource),
|
||||
},
|
||||
want: "cpe:2.3:a:ruby-lang:openssl:1.0.2k:*:*:*:*:*:*:*",
|
||||
// without the cpe data wired up, this would be empty (generation also creates cpe:2.3:a:openssl:openssl:1.0.2k:*:*:*:*:*:*:*)
|
||||
wantExists: true,
|
||||
},
|
||||
@@ -1013,7 +1009,8 @@ func TestDictionaryFindIsWired(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, gotExists := FromDictionaryFind(tt.pkg)
|
||||
assert.ElementsMatch(t, tt.want, got)
|
||||
|
||||
assert.Equal(t, tt.want, got.Attributes.BindToFmtString())
|
||||
assert.Equal(t, tt.wantExists, gotExists)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -181,13 +181,6 @@ func (j *archiveParser) discoverMainPackage(ctx context.Context) (*pkg.Package,
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// check for existence of Weave-Classes manifest key in order to exclude jars getting misrepresented as
|
||||
// their targeted counterparts, e.g. newrelic spring and tomcat instrumentation
|
||||
if _, ok := manifest.Main.Get("Weave-Classes"); ok {
|
||||
log.Debugf("excluding archive due to Weave-Classes manifest entry: %s", j.location)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// grab and assign digest for the entire archive
|
||||
digests, err := getDigestsFromArchive(j.archivePath)
|
||||
if err != nil {
|
||||
|
||||
@@ -1168,6 +1168,7 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
|
||||
expectedPkgs []pkg.Package
|
||||
expectedRelationships []artifact.Relationship
|
||||
assignParent bool
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "duplicate jar regression - go case (issue #2130)",
|
||||
@@ -1350,11 +1351,6 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "exclude instrumentation jars with Weave-Classes in manifest",
|
||||
fixtureName: "spring-instrumentation-4.3.0-1.0",
|
||||
expectedPkgs: nil, // we expect no packages to be discovered when Weave-Classes present in the manifest
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -26,7 +26,7 @@ func packageURL(name, version string, metadata pkg.JavaArchive) string {
|
||||
return pURL.ToString()
|
||||
}
|
||||
|
||||
// groupIDFromJavaMetadata returns the authoritative group ID for a Java package.
|
||||
// GroupIDFromJavaPackage returns the authoritative group ID for a Java package.
|
||||
// The order of precedence is:
|
||||
// 1. The group ID from the POM properties
|
||||
// 2. The group ID from the POM project
|
||||
|
||||
@@ -230,30 +230,16 @@ func cleanDescription(original *string) (cleaned string) {
|
||||
// resolveProperty emulates some maven property resolution logic by looking in the project's variables
|
||||
// as well as supporting the project expressions like ${project.parent.groupId}.
|
||||
// If no match is found, the entire expression including ${} is returned
|
||||
//
|
||||
//nolint:gocognit
|
||||
func resolveProperty(pom gopom.Project, property *string, propertyName string) string {
|
||||
propertyCase := safeString(property)
|
||||
log.WithFields("existingPropertyValue", propertyCase, "propertyName", propertyName).Trace("resolving property")
|
||||
seenBeforePropertyNames := map[string]struct{}{
|
||||
propertyName: {},
|
||||
}
|
||||
result := recursiveResolveProperty(pom, propertyCase, seenBeforePropertyNames)
|
||||
if propertyMatcher.MatchString(result) {
|
||||
return "" // dereferencing variable failed; fall back to empty string
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
//nolint:gocognit
|
||||
func recursiveResolveProperty(pom gopom.Project, propertyCase string, seenPropertyNames map[string]struct{}) string {
|
||||
return propertyMatcher.ReplaceAllStringFunc(propertyCase, func(match string) string {
|
||||
propertyName := strings.TrimSpace(match[2 : len(match)-1]) // remove leading ${ and trailing }
|
||||
if _, seen := seenPropertyNames[propertyName]; seen {
|
||||
return propertyCase
|
||||
}
|
||||
entries := pomProperties(pom)
|
||||
if value, ok := entries[propertyName]; ok {
|
||||
seenPropertyNames[propertyName] = struct{}{}
|
||||
return recursiveResolveProperty(pom, value, seenPropertyNames) // recursively resolve in case a variable points to a variable.
|
||||
return value
|
||||
}
|
||||
|
||||
// if we don't find anything directly in the pom properties,
|
||||
|
||||
@@ -502,7 +502,7 @@ func Test_resolveProperty(t *testing.T) {
|
||||
pom: gopom.Project{
|
||||
Parent: nil,
|
||||
},
|
||||
expected: "",
|
||||
expected: "${project.parent.groupId}",
|
||||
},
|
||||
{
|
||||
name: "nil string pointer halts search",
|
||||
@@ -512,90 +512,7 @@ func Test_resolveProperty(t *testing.T) {
|
||||
GroupID: nil,
|
||||
},
|
||||
},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "double dereference",
|
||||
property: "${springboot.version}",
|
||||
pom: gopom.Project{
|
||||
Parent: &gopom.Parent{
|
||||
Version: stringPointer("1.2.3"),
|
||||
},
|
||||
Properties: &gopom.Properties{
|
||||
Entries: map[string]string{
|
||||
"springboot.version": "${project.parent.version}",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "1.2.3",
|
||||
},
|
||||
{
|
||||
name: "map missing stops double dereference",
|
||||
property: "${springboot.version}",
|
||||
pom: gopom.Project{
|
||||
Parent: &gopom.Parent{
|
||||
Version: stringPointer("1.2.3"),
|
||||
},
|
||||
},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "resolution halts even if it resolves to a variable",
|
||||
property: "${springboot.version}",
|
||||
pom: gopom.Project{
|
||||
Parent: &gopom.Parent{
|
||||
Version: stringPointer("${undefined.version}"),
|
||||
},
|
||||
Properties: &gopom.Properties{
|
||||
Entries: map[string]string{
|
||||
"springboot.version": "${project.parent.version}",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "resolution halts even if cyclic",
|
||||
property: "${springboot.version}",
|
||||
pom: gopom.Project{
|
||||
Properties: &gopom.Properties{
|
||||
Entries: map[string]string{
|
||||
"springboot.version": "${springboot.version}",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "resolution halts even if cyclic more steps",
|
||||
property: "${cyclic.version}",
|
||||
pom: gopom.Project{
|
||||
Properties: &gopom.Properties{
|
||||
Entries: map[string]string{
|
||||
"other.version": "${cyclic.version}",
|
||||
"springboot.version": "${other.version}",
|
||||
"cyclic.version": "${springboot.version}",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "resolution halts even if cyclic involving parent",
|
||||
property: "${cyclic.version}",
|
||||
pom: gopom.Project{
|
||||
Parent: &gopom.Parent{
|
||||
Version: stringPointer("${cyclic.version}"),
|
||||
},
|
||||
Properties: &gopom.Properties{
|
||||
Entries: map[string]string{
|
||||
"other.version": "${parent.version}",
|
||||
"springboot.version": "${other.version}",
|
||||
"cyclic.version": "${springboot.version}",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "",
|
||||
expected: "${project.parent.groupId}",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ JACKSON_CORE = jackson-core-2.15.2
|
||||
SBT_JACKSON_CORE = com.fasterxml.jackson.core.jackson-core-2.15.2
|
||||
OPENSAML_CORE = opensaml-core-3.4.6
|
||||
API_ALL_SOURCES = api-all-2.0.0-sources
|
||||
SPRING_INSTRUMENTATION = spring-instrumentation-4.3.0-1.0
|
||||
|
||||
$(CACHE_DIR):
|
||||
mkdir -p $(CACHE_DIR)
|
||||
@@ -20,7 +19,4 @@ $(CACHE_DIR)/$(OPENSAML_CORE).jar: $(CACHE_DIR)
|
||||
cd $(OPENSAML_CORE) && zip -r $(CACHE_PATH)/$(OPENSAML_CORE).jar .
|
||||
|
||||
$(CACHE_DIR)/$(API_ALL_SOURCES).jar: $(CACHE_DIR)
|
||||
cd $(API_ALL_SOURCES) && zip -r $(CACHE_PATH)/$(API_ALL_SOURCES).jar .
|
||||
|
||||
$(CACHE_DIR)/$(SPRING_INSTRUMENTATION).jar: $(CACHE_DIR)
|
||||
cd $(SPRING_INSTRUMENTATION) && zip -r $(CACHE_PATH)/$(SPRING_INSTRUMENTATION).jar .
|
||||
cd $(API_ALL_SOURCES) && zip -r $(CACHE_PATH)/$(API_ALL_SOURCES).jar .
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
Manifest-Version: 1.0
|
||||
Implementation-Title: com.newrelic.instrumentation.spring-4.3.0
|
||||
Implementation-Version: 1.0
|
||||
Illegal-Classes:
|
||||
Weave-Violation-Filter: METHOD_MISSING_REQUIRED_ANNOTATIONS,CLASS_MISS
|
||||
ING_REQUIRED_ANNOTATIONS
|
||||
Reference-Classes: org/springframework/core/annotation/AnnotationUtils
|
||||
,org/springframework/web/bind/annotation/DeleteMapping,org/springfram
|
||||
ework/web/bind/annotation/PatchMapping,org/springframework/web/bind/a
|
||||
nnotation/PostMapping,org/springframework/web/bind/annotation/PutMapp
|
||||
ing,org/springframework/web/bind/annotation/RequestMapping,org/spring
|
||||
framework/web/method/HandlerMethod,org/springframework/web/servlet/Mo
|
||||
delAndView
|
||||
Class-Required-Annotations:
|
||||
Method-Required-Annotations:
|
||||
Implementation-Title-Alias: spring_annotations
|
||||
Weave-Classes: org/springframework/web/bind/annotation/GetMapping,org/
|
||||
springframework/web/servlet/mvc/method/AbstractHandlerMethodAdapter
|
||||
Weave-Methods: "handleInternal(Ljavax/servlet/http/HttpServletRequest;
|
||||
Ljavax/servlet/http/HttpServletResponse;Lorg/springframework/web/meth
|
||||
od/HandlerMethod;)Lorg/springframework/web/servlet/ModelAndView;"
|
||||
Implementation-Vendor: New Relic
|
||||
@@ -17,9 +17,8 @@ func NewPackageCataloger() pkg.Cataloger {
|
||||
// NewLockCataloger returns a new cataloger object for NPM (and NPM-adjacent, such as yarn) lock files.
|
||||
func NewLockCataloger(cfg CatalogerConfig) pkg.Cataloger {
|
||||
yarnLockAdapter := newGenericYarnLockAdapter(cfg)
|
||||
packageLockAdapter := newGenericPackageLockAdapter(cfg)
|
||||
return generic.NewCataloger("javascript-lock-cataloger").
|
||||
WithParserByGlobs(packageLockAdapter.parsePackageLock, "**/package-lock.json").
|
||||
WithParserByGlobs(parsePackageLock, "**/package-lock.json").
|
||||
WithParserByGlobs(yarnLockAdapter.parseYarnLock, "**/yarn.lock").
|
||||
WithParserByGlobs(parsePnpmLock, "**/pnpm-lock.yaml")
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func newPackageJSONPackage(u packageJSON, indexLocation file.Location) pkg.Packa
|
||||
return p
|
||||
}
|
||||
|
||||
func newPackageLockV1Package(cfg CatalogerConfig, resolver file.Resolver, location file.Location, name string, u lockDependency) pkg.Package {
|
||||
func newPackageLockV1Package(resolver file.Resolver, location file.Location, name string, u lockDependency) pkg.Package {
|
||||
version := u.Version
|
||||
|
||||
const aliasPrefixPackageLockV1 = "npm:"
|
||||
@@ -63,26 +63,12 @@ func newPackageLockV1Package(cfg CatalogerConfig, resolver file.Resolver, locati
|
||||
version = canonicalPackageAndVersion[versionSeparator+1:]
|
||||
}
|
||||
|
||||
var licenseSet pkg.LicenseSet
|
||||
|
||||
if cfg.SearchRemoteLicenses {
|
||||
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
|
||||
if err == nil && license != "" {
|
||||
licenses := pkg.NewLicensesFromValues(license)
|
||||
licenseSet = pkg.NewLicenseSet(licenses...)
|
||||
}
|
||||
if err != nil {
|
||||
log.Warnf("unable to extract licenses from javascript yarn.lock for package %s:%s: %+v", name, version, err)
|
||||
}
|
||||
}
|
||||
|
||||
return finalizeLockPkg(
|
||||
resolver,
|
||||
location,
|
||||
pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Licenses: licenseSet,
|
||||
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(name, version),
|
||||
Language: pkg.JavaScript,
|
||||
@@ -92,22 +78,7 @@ func newPackageLockV1Package(cfg CatalogerConfig, resolver file.Resolver, locati
|
||||
)
|
||||
}
|
||||
|
||||
func newPackageLockV2Package(cfg CatalogerConfig, resolver file.Resolver, location file.Location, name string, u lockPackage) pkg.Package {
|
||||
var licenseSet pkg.LicenseSet
|
||||
|
||||
if u.License != nil {
|
||||
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocation(location, u.License...)...)
|
||||
} else if cfg.SearchRemoteLicenses {
|
||||
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, u.Version)
|
||||
if err == nil && license != "" {
|
||||
licenses := pkg.NewLicensesFromValues(license)
|
||||
licenseSet = pkg.NewLicenseSet(licenses...)
|
||||
}
|
||||
if err != nil {
|
||||
log.Warnf("unable to extract licenses from javascript yarn.lock for package %s:%s: %+v", name, u.Version, err)
|
||||
}
|
||||
}
|
||||
|
||||
func newPackageLockV2Package(resolver file.Resolver, location file.Location, name string, u lockPackage) pkg.Package {
|
||||
return finalizeLockPkg(
|
||||
resolver,
|
||||
location,
|
||||
@@ -115,7 +86,7 @@ func newPackageLockV2Package(cfg CatalogerConfig, resolver file.Resolver, locati
|
||||
Name: name,
|
||||
Version: u.Version,
|
||||
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
Licenses: licenseSet,
|
||||
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocation(location, u.License...)...),
|
||||
PURL: packageURL(name, u.Version),
|
||||
Language: pkg.JavaScript,
|
||||
Type: pkg.NpmPkg,
|
||||
|
||||
@@ -15,6 +15,9 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ generic.Parser = parsePackageLock
|
||||
|
||||
// packageLock represents a JavaScript package.lock json file
|
||||
type packageLock struct {
|
||||
Requires bool `json:"requires"`
|
||||
@@ -41,18 +44,8 @@ type lockPackage struct {
|
||||
// packageLockLicense
|
||||
type packageLockLicense []string
|
||||
|
||||
type genericPackageLockAdapter struct {
|
||||
cfg CatalogerConfig
|
||||
}
|
||||
|
||||
func newGenericPackageLockAdapter(cfg CatalogerConfig) genericPackageLockAdapter {
|
||||
return genericPackageLockAdapter{
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
// parsePackageLock parses a package-lock.json and returns the discovered JavaScript packages.
|
||||
func (a genericPackageLockAdapter) parsePackageLock(_ context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
func parsePackageLock(_ context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
// in the case we find package-lock.json files in the node_modules directories, skip those
|
||||
// as the whole purpose of the lock file is for the specific dependencies of the root project
|
||||
if pathContainsNodeModulesDirectory(reader.Path()) {
|
||||
@@ -73,7 +66,7 @@ func (a genericPackageLockAdapter) parsePackageLock(_ context.Context, resolver
|
||||
|
||||
if lock.LockfileVersion == 1 {
|
||||
for name, pkgMeta := range lock.Dependencies {
|
||||
pkgs = append(pkgs, newPackageLockV1Package(a.cfg, resolver, reader.Location, name, pkgMeta))
|
||||
pkgs = append(pkgs, newPackageLockV1Package(resolver, reader.Location, name, pkgMeta))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +86,7 @@ func (a genericPackageLockAdapter) parsePackageLock(_ context.Context, resolver
|
||||
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
newPackageLockV2Package(a.cfg, resolver, reader.Location, getNameFromPath(name), pkgMeta),
|
||||
newPackageLockV2Package(resolver, reader.Location, getNameFromPath(name), pkgMeta),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,8 +106,7 @@ func TestParsePackageLock(t *testing.T) {
|
||||
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
||||
}
|
||||
|
||||
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||
pkgtest.TestFileParser(t, fixture, adapter.parsePackageLock, expectedPkgs, expectedRelationships)
|
||||
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
|
||||
}
|
||||
|
||||
func TestParsePackageLockV2(t *testing.T) {
|
||||
@@ -170,8 +169,7 @@ func TestParsePackageLockV2(t *testing.T) {
|
||||
for i := range expectedPkgs {
|
||||
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
||||
}
|
||||
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||
pkgtest.TestFileParser(t, fixture, adapter.parsePackageLock, expectedPkgs, expectedRelationships)
|
||||
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
|
||||
}
|
||||
|
||||
func TestParsePackageLockV3(t *testing.T) {
|
||||
@@ -222,8 +220,7 @@ func TestParsePackageLockV3(t *testing.T) {
|
||||
for i := range expectedPkgs {
|
||||
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
||||
}
|
||||
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||
pkgtest.TestFileParser(t, fixture, adapter.parsePackageLock, expectedPkgs, expectedRelationships)
|
||||
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
|
||||
}
|
||||
|
||||
func TestParsePackageLockAlias(t *testing.T) {
|
||||
@@ -282,8 +279,7 @@ func TestParsePackageLockAlias(t *testing.T) {
|
||||
for i := range expected {
|
||||
expected[i].Locations.Add(file.NewLocation(pl))
|
||||
}
|
||||
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||
pkgtest.TestFileParser(t, pl, adapter.parsePackageLock, expected, expectedRelationships)
|
||||
pkgtest.TestFileParser(t, pl, parsePackageLock, expected, expectedRelationships)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,6 +326,5 @@ func TestParsePackageLockLicenseWithArray(t *testing.T) {
|
||||
for i := range expectedPkgs {
|
||||
expectedPkgs[i].Locations.Add(file.NewLocation(fixture))
|
||||
}
|
||||
adapter := newGenericPackageLockAdapter(CatalogerConfig{})
|
||||
pkgtest.TestFileParser(t, fixture, adapter.parsePackageLock, expectedPkgs, expectedRelationships)
|
||||
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
|
||||
}
|
||||
|
||||
@@ -22,9 +22,3 @@ func NewComposerLockCataloger() pkg.Cataloger {
|
||||
return generic.NewCataloger("php-composer-lock-cataloger").
|
||||
WithParserByGlobs(parseComposerLock, "**/composer.lock")
|
||||
}
|
||||
|
||||
// NewPeclCataloger returns a new cataloger for PHP PECL metadata“.
|
||||
func NewPeclCataloger() pkg.Cataloger {
|
||||
return generic.NewCataloger("php-pecl-serialized-cataloger").
|
||||
WithParserByGlobs(parsePeclSerialized, "**/php/.registry/.channel.*/*.reg")
|
||||
}
|
||||
|
||||
@@ -55,28 +55,3 @@ func Test_ComposerLockCataloger_Globs(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PeclCataloger_Globs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "obtain pecl files",
|
||||
fixture: "test-fixtures/glob-paths",
|
||||
expected: []string{
|
||||
"php/.registry/.channel.pecl.php.net/memcached.reg",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
pkgtest.NewCatalogTester().
|
||||
FromDirectory(t, test.fixture).
|
||||
ExpectsResolverContentQueries(test.expected).
|
||||
TestCataloger(t, NewPeclCataloger())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,22 +40,6 @@ func newComposerInstalledPackage(pd parsedInstalledData, indexLocation file.Loca
|
||||
return p
|
||||
}
|
||||
|
||||
func newPeclPackage(pd pkg.PhpPeclEntry, indexLocation file.Location) pkg.Package {
|
||||
p := pkg.Package{
|
||||
Name: pd.Name,
|
||||
Version: pd.Version,
|
||||
Locations: file.NewLocationSet(indexLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocation(indexLocation, pd.License...)...),
|
||||
PURL: packageURLFromPecl(pd.Name, pd.Version),
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpPeclPkg,
|
||||
Metadata: pd,
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
return p
|
||||
}
|
||||
|
||||
func packageURL(name, version string) string {
|
||||
var pkgName, vendor string
|
||||
fields := strings.Split(name, "/")
|
||||
@@ -81,14 +65,3 @@ func packageURL(name, version string) string {
|
||||
"")
|
||||
return pURL.ToString()
|
||||
}
|
||||
|
||||
func packageURLFromPecl(pkgName, version string) string {
|
||||
pURL := packageurl.NewPackageURL(
|
||||
"pecl",
|
||||
"",
|
||||
pkgName,
|
||||
version,
|
||||
nil,
|
||||
"")
|
||||
return pURL.ToString()
|
||||
}
|
||||
|
||||
@@ -44,28 +44,3 @@ func Test_packageURL(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_packageURLFromPecl(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
version string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "memcached",
|
||||
version: "3.2.0",
|
||||
expected: "pkg:pecl/memcached@3.2.0",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := packageURLFromPecl(test.name, test.version)
|
||||
if actual != test.expected {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(test.expected, actual, true)
|
||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
package php
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/elliotchance/phpserialize"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// parsePeclSerialized is a parser function for PECL metadata contents, returning "Default" php packages discovered.
|
||||
func parsePeclSerialized(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
var pkgs []pkg.Package
|
||||
data, err := io.ReadAll(reader)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to read file: %w", err)
|
||||
}
|
||||
|
||||
metadata, err := phpserialize.UnmarshalAssociativeArray(
|
||||
data,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse pecl metadata file: %w", err)
|
||||
}
|
||||
|
||||
name, ok := metadata["name"].(string)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("failed to parse pecl package name: %w", err)
|
||||
}
|
||||
|
||||
version := readStruct(metadata, "version", "release")
|
||||
license := readStruct(metadata, "license", "_content")
|
||||
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
newPeclPackage(
|
||||
pkg.PhpPeclEntry{
|
||||
Name: name,
|
||||
Version: version,
|
||||
License: []string{
|
||||
license,
|
||||
},
|
||||
},
|
||||
reader.Location,
|
||||
),
|
||||
)
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
func readStruct(metadata any, fields ...string) string {
|
||||
if len(fields) > 0 {
|
||||
value, ok := metadata.(map[any]any)
|
||||
if !ok {
|
||||
log.Tracef("unable to read '%s' from: %v", fields[0], metadata)
|
||||
return ""
|
||||
}
|
||||
return readStruct(value[fields[0]], fields[1:]...)
|
||||
}
|
||||
value, ok := metadata.(string)
|
||||
if !ok {
|
||||
log.Tracef("unable to read value from: %v", metadata)
|
||||
}
|
||||
return value
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user