Compare commits

...
Author SHA1 Message Date
Alex Goodman dfde0974b0 address reading archives into memory
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-05-13 10:56:57 -04:00
Will Bates 9f047fdf11 fix: detect compressed kernel modules (.ko.gz, .ko.xz, .ko.zst)
The linux-kernel-cataloger only matched plain *.ko files, missing
compressed modules produced when CONFIG_MODULE_COMPRESS is enabled
(common on Debian 13 / Ubuntu 24.04+). This resulted in near-zero
module packages being reported for such filesystems.

Changes:
- Add *.ko.gz, *.ko.xz, *.ko.zst glob patterns to both the cataloger
  and capabilities.yaml so the file resolver picks up compressed modules
- Add decompressedModuleReader() which detects the extension and
  transparently decompresses via compress/gzip, ulikunitz/xz, or
  klauspost/compress/zstd before handing the ELF bytes to the existing
  parseLinuxKernelModuleMetadata parser
- Promote github.com/klauspost/compress from indirect to direct dependency
- Add unit tests covering all three compression formats plus the
  uncompressed baseline, using a programmatically generated minimal ELF

Fixes #4721

Signed-off-by: Will Bates <william.bates11@outlook.com>
2026-05-13 10:08:53 -04:00
anchore-oss-update-botandanchore-oss-update-bot 07ae2ca08d chore(deps): update CPE dictionary index (#4909)
Signed-off-by: anchore-oss-update-bot <anchore-oss-update-bot@users.noreply.github.com>
Co-authored-by: anchore-oss-update-bot <anchore-oss-update-bot@users.noreply.github.com>
2026-05-13 10:03:11 -04:00
36969bdeff fix: Allow duplicates in Yarn "Berry" files (#4691) (#4838)
* fix: Allow duplicates in Yarn "Berry" files (#4691)

Yarn lockfiles can have multiple versions resolved for the same package
name. We correctly allow this in Yarn v1 lockfiles but the "Berry"
YAML-format lockfiles were doing deduplication by package name. This
change removes that deduplication.

Signed-off-by: Calum Leslie <cleslie@atlassian.com>

* fix linting

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

---------

Signed-off-by: Calum Leslie <cleslie@atlassian.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Calum Leslie <cleslie@atlassian.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-05-11 21:10:17 +00:00
Alex Goodman dfb6011083 pin and update fixture versions (#4913)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-05-11 16:30:35 -04:00
Alex Goodman 997a486e22 use released shared workflow (#4914)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-05-11 16:21:41 -04:00
dependabot[bot] 4f64fbc004 chore(deps): bump github.com/go-git/go-git/v5 from 5.18.0 to 5.19.0 (#4911)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.18.0 to 5.19.0.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Changelog](https://github.com/go-git/go-git/blob/main/HISTORY.md)
- [Commits](https://github.com/go-git/go-git/compare/v5.18.0...v5.19.0)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-version: 5.19.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-11 16:25:44 +00:00
Alex Goodman 87d6a288d7 Tighten workflow permissions and update release shape (#4899)
* Rework release workflow to canonical shape

Replace the custom quality-gate job with the reusable check-version-available
and check-gate workflows from anchore/workflows. Remove the phase
workflow_dispatch input; the install-script-only path is now a standalone
workflow (release-install-script.yaml) that can be triggered independently.

- add version-available and check-gate jobs using pinned anchore/workflows SHA
- remove phase input and quality-gate job
- release job now needs [check-gate, version-available]
- release-install-script job no longer conditionally skips based on phase
- add release-install-script.yaml for standalone install script runs
- set permissions: {} at workflow level (contents pushed to release job)
- add concurrency: group: release

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

* Tighten workflow-level permissions to {}

Change top-level permissions from contents: read to {} in validations.yaml
and validate-github-actions.yaml, pushing the needed contents: read down
to each job that performs a checkout.

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

* keep install script phase, remove workflow

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

* remove schema detection workflow

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

---------

Signed-off-by: wagoodman <wagoodman@gmail.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-05-08 17:16:31 -04:00
dependabot[bot] 20987d30d0 chore(deps): bump the actions-minor-patch group across 1 directory with 2 updates (#4897)
Bumps the actions-minor-patch group with 2 updates in the / directory: [github/codeql-action](https://github.com/github/codeql-action) and [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action).


Updates `github/codeql-action` from 4.35.2 to 4.35.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/95e58e9a2cdfd71adc6e0353d5c52f41a045d225...e46ed2cbd01164d986452f91f178727624ae40d7)

Updates `slackapi/slack-github-action` from 3.0.2 to 3.0.3
- [Release notes](https://github.com/slackapi/slack-github-action/releases)
- [Changelog](https://github.com/slackapi/slack-github-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slackapi/slack-github-action/compare/03ea5433c137af7c0495bc0cad1af10403fc800c...45a88b9581bfab2566dc881e2cd66d334e621e2c)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-minor-patch
- dependency-name: slackapi/slack-github-action
  dependency-version: 3.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-08 13:38:31 +00:00
witchcraze e2007d9bf2 feat: add aws-lc classifier (#4882)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2026-05-06 16:43:34 -04:00
ChrisJr404andChris 4f0e32ab51 binary classifier: detect elixir release-candidate versions (#4851)
The elixir-binary and elixir-library classifiers' regexes only matched
the bare semver triplet (and a single sub-segment for the library), so
release-candidate elixir images were either missed entirely or had
their version truncated:

  $ syft -q elixir:1.12.0-rc | grep elixir   # nothing
  $ syft -q elixir:1.13.0-rc.0 | grep elixir
  elixir   1.13.0   binary                   # truncated, "-rc.0" lost

Extend the version capture group to optionally include
"-<a-z0-9>+(\\.<digits>)?" so "1.12.0-rc.1", "1.13.0-rc.0", etc. match
exactly as the elixir.app and the binary's ELIXIR_VERSION line have
them.

Add a logical fixture under testdata/classifiers/snippets/elixir/
1.12.0-rc.1/linux-amd64 (cloned from the existing 1.19.1 fixture with
just the version strings changed) and register it in
Test_Cataloger_PositiveCases.

Closes #4819

Signed-off-by: Chris (ChrisJr404) <11917633+ChrisJr404@users.noreply.github.com>
Co-authored-by: Chris (ChrisJr404) <11917633+ChrisJr404@users.noreply.github.com>
2026-05-06 15:14:09 +00:00
witchcraze 605391114c add ingress-nginx classifier (#4857)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2026-05-06 14:54:20 +00:00
ChrisJr404 1caf243d29 fix(source): treat exclude paths with trailing slash as directories (#4892)
A trailing slash on --exclude (e.g. './lib/') is dropped during pattern
normalization but doublestar.Match still requires an exact string match,
so the resulting pattern silently matches nothing and the directory is
not excluded. Strip a trailing slash so './lib/' and './lib' behave the
same.

Fixes #4839

Signed-off-by: ChrisJr404 <chris@hacknow.com>
2026-05-06 14:51:41 +00:00
PGrayandPGray 48e91312e8 fix(dotnet): align runtime CPEs with NVD (#4743)
Signed-off-by: PGray <PGrayCS@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: PGray <PGrayCS@users.noreply.github.com>
2026-05-06 13:07:49 +00:00
d81df67493 fix(debian): only parse machine-readable copyright files with Format header (#4754)
* fix(debian): only parse machine-readable copyright files with Format header

Only parse debian/copyright files as machine-readable DEP-5 format when
they contain the mandatory Format header field pointing to the copyright
specification URI. Files without this header are free-form text and
should not have License: regex patterns applied to them, which previously
produced nonsensical results like "#", "Permission", "This", "see" for
non-machine-readable files.

The fallback license classifier in the debian cataloger will handle
non-machine-readable files by doing full-text license identification.

Closes #4708

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

* decompose parseLicensesFromCopyright to address linting issues

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

---------

Signed-off-by: Bahtya <bahtya@users.noreply.github.com>
Signed-off-by: Bahtya <bahtayr@gmail.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Bahtya <bahtayr@gmail.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-05-06 13:02:27 +00:00
dependabot[bot] 47cda2b5ef chore(deps): bump the actions-minor-patch group across 2 directories with 5 updates (#4846)
Bumps the actions-minor-patch group with 4 updates in the / directory: [github/codeql-action](https://github.com/github/codeql-action), [marocchino/sticky-pull-request-comment](https://github.com/marocchino/sticky-pull-request-comment), [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) and [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action).
Bumps the actions-minor-patch group with 1 update in the /.github/actions/bootstrap directory: [actions/cache](https://github.com/actions/cache).


Updates `github/codeql-action` from 4.35.1 to 4.35.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/c10b8064de6f491fea524254123dbe5e09572f13...95e58e9a2cdfd71adc6e0353d5c52f41a045d225)

Updates `marocchino/sticky-pull-request-comment` from 3.0.3 to 3.0.4
- [Release notes](https://github.com/marocchino/sticky-pull-request-comment/releases)
- [Commits](https://github.com/marocchino/sticky-pull-request-comment/compare/d4d6b0936434b21bc8345ad45a440c5f7d2c40ff...0ea0beb66eb9baf113663a64ec522f60e49231c0)

Updates `slackapi/slack-github-action` from 3.0.1 to 3.0.2
- [Release notes](https://github.com/slackapi/slack-github-action/releases)
- [Changelog](https://github.com/slackapi/slack-github-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slackapi/slack-github-action/compare/af78098f536edbc4de71162a307590698245be95...03ea5433c137af7c0495bc0cad1af10403fc800c)

Updates `zizmorcore/zizmor-action` from 0.5.2 to 0.5.3
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](https://github.com/zizmorcore/zizmor-action/compare/71321a20a9ded102f6e9ce5718a2fcec2c4f70d8...b1d7e1fb5de872772f31590499237e7cce841e8e)

Updates `actions/cache` from 5.0.4 to 5.0.5
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/668228422ae6a00e4ad889ee87cd7109ec5666a7...27d5ce7f107fe9357f9df03efb73ab90386fccae)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-minor-patch
- dependency-name: marocchino/sticky-pull-request-comment
  dependency-version: 3.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-minor-patch
- dependency-name: slackapi/slack-github-action
  dependency-version: 3.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-minor-patch
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.5.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-minor-patch
- dependency-name: actions/cache
  dependency-version: 5.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 11:42:04 -04:00
Rayan Salhabandcyphercodes ae711963d1 fix: parse arbitrary equality python requirements (#4835)
Signed-off-by: cyphercodes <cyphercodes@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
2026-05-05 13:49:03 +00:00
Alex Goodman f878197150 chore: remove common workflows (#4881)
Removes deprecated common workflows now centralized elsewhere.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-05-04 14:31:07 -04:00
witchcraze 514efb03e0 fix: prevent redis classifier from detecting valkey (#4619)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2026-05-04 14:07:29 -04:00
anchore-oss-update-botandanchore-oss-update-bot 1e4f424f09 chore(deps): update CPE dictionary index (#4831)
Signed-off-by: anchore-oss-update-bot <anchore-oss-update-bot@users.noreply.github.com>
Co-authored-by: anchore-oss-update-bot <anchore-oss-update-bot@users.noreply.github.com>
2026-05-04 10:14:08 -04:00
ChrisJr404 b5f0877967 fix: map "nuget" purl type to DotnetPkg in TypeByName (#4848)
Signed-off-by: Chris (ChrisJr404) <11917633+ChrisJr404@users.noreply.github.com>
2026-05-04 08:51:19 -04:00
Rayan Salhab 8cb78ce40c fix: resolve yarn lock aliases to source package (#4836)
Signed-off-by: cyphercodes <cyphercodes@users.noreply.github.com>
2026-04-29 09:50:09 -04:00
witchcraze 3b046b3787 chore: move snippet files from test-fixtures to testdata (#4830)
Signed-off-by: witchcraze <witchcraze@gmail.com>
2026-04-27 11:09:21 -04:00
Ludovic Henry 05cc8ee5f4 Add support for linux-riscv64 (#4757) 2026-04-27 10:21:41 +00:00
Akihiko Komada 3562dab445 fix(lua-rockspec): handle empty and whitespace-only rockspec files gracefully (#4827)
Empty or whitespace-only .rockspec files cause parseRockspecBlock to
panic with "index out of range" because the existing end-of-data guard
requires len(out) > 0 before returning the "unexpected end of block"
error, letting the bare data[*i] access on the next line crash.

Split the guard so that:
  - partial content at end of data still returns the existing error
  - empty data (or whitespace-only) returns an empty block cleanly

Closes #4824.

Signed-off-by: Akihiko Komada <aki1770@gmail.com>
2026-04-24 12:44:25 -04:00
Sebastiaan van Stijn 014a4c9c59 chore: tidy go.mod (#4823)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-04-23 18:07:11 -04:00
Rez Moss 3cb838eacf fixed pe dotnet wrong ver , fixed #4813 (#4814)
Signed-off-by: Rez Moss <hi@rezmoss.com>
2026-04-22 20:55:56 -04:00
Sai Asish Y 758324b3e8 fix: propagate non-EOF errors out of safeCopy (#4807)
Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>
2026-04-22 12:06:03 -04:00
71 changed files with 2241 additions and 885 deletions
+2 -2
View File
@@ -35,7 +35,7 @@ runs:
- name: Restore tool cache
if: inputs.tools == 'true'
id: tool-cache
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ github.workspace }}/.tool
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('.binny.yaml') }}
@@ -60,7 +60,7 @@ runs:
DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y "${packages[@]}"
- name: Restore ORAS cache from github actions
if: inputs.download-test-fixture-cache == 'true'
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ github.workspace }}/.tmp/oras-cache
key: ${{ inputs.cache-key-prefix }}-oras-cache
+4 -64
View File
@@ -1,6 +1,3 @@
# CodeQL scans for security vulnerabilities and coding errors across all
# languages in this repo. Results appear in the "Security" tab under
# "Code scanning alerts" and are enforced by branch protection rules.
name: "CodeQL"
on:
@@ -8,74 +5,17 @@ on:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# Weekly scheduled scan catches newly disclosed vulnerabilities in
# existing code, not just changes introduced by PRs.
schedule:
- cron: '38 11 * * 3'
permissions: {}
jobs:
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest
name: Analyze
uses: anchore/workflows/.github/workflows/codeql.yaml@e8cee3a5916cebb68cda68b54c180f43394c1910 # v0.5.0
permissions:
# Required to upload SARIF results to the "Security" tab.
security-events: write
# Required to fetch internal or private CodeQL packs.
packages: read
# Only required for workflows in private repositories.
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
# GitHub Actions workflow linting — no build needed.
- language: actions
build-mode: none
# Go uses "manual" build mode so we control exactly what gets
# compiled. The default "autobuild" finds the Makefile and runs
# the full CI pipeline (lint, test, snapshot release, etc.),
# which is far more work than CodeQL needs. All it requires is
# compiled Go source so it can build a type-resolved code graph
# for analysis.
- language: go
build-mode: manual
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Pin the Go toolchain to whatever go.mod declares so CodeQL
# analyzes with the same version the project actually uses.
# Only runs for the Go matrix entry.
- name: Setup Go
if: matrix.language == 'go'
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
- name: Initialize CodeQL
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# Minimal build for Go: compile all packages so CodeQL gets a full
# type-resolved code graph for analysis.
- name: Build (Go)
if: matrix.build-mode == 'manual'
shell: bash
run: go build ./...
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
# The category tag lets GitHub associate SARIF results with the
# correct language when branch protection checks for required
# code scanning results.
category: "/language:${{matrix.language}}"
@@ -1,10 +0,0 @@
name: Dependabot Automation
on:
pull_request:
permissions:
pull-requests: write
jobs:
run:
uses: anchore/workflows/.github/workflows/dependabot-automation.yaml@main
@@ -1,64 +0,0 @@
# Note: this workflow has been disabled manually in the UI and will be replaced in short order
name: "Detect schema changes"
on:
# IMPORTANT! This workflow is triggered by the `pull_request_target` event
# which means that forked PRs will run with access secrets from the repo
# it's forked from (the "target" repo).
#
# For this reason we only NEVER checkout the code from the pull request
# (e.g. "ref: ${{ github.event.pull_request.head.sha }}") to prevent
# accidentally running potentially untrusted code.
#
# By default the checkout will be:
# - GITHUB_SHA: Last commit on the PR base branch
# - GITHUB_REF: PR base branch
#
# ...unlike a typical PR where:
# - GITHUB_SHA: Last merge commit on the GITHUB_REF branch
# - GITHUB_REF: PR merge branch refs/pull/:prNumber/merge
pull_request_target:
env:
# note: this is used within hashFiles() so must be within the GITHUB_WORKSPACE path (or will silently fail)
CI_COMMENT_FILE: .tmp/labeler-comment.txt
# needs to be any string to uniquely identify the comment on a PR across multiple runs
COMMENT_HEADER: "label-commentary"
jobs:
label:
name: "Label changes"
runs-on: ubuntu-22.04
permissions:
contents: read
pull-requests: write
issues: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
persist-credentials: false
repository: anchore/syft # IMPORTANT! An additional protection that this is checking out code from the expected repository
ref: main # IMPORTANT! It is CRITICAL that this only ever considers the code from main and NEVER EVER from a fork.
- run: python .github/scripts/labeler.py
env:
# note: this token has write access to the repo
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PR_NUMBER: ${{ github.event.number }}
- name: Delete existing comment
if: ${{ hashFiles( env.CI_COMMENT_FILE ) == '' }}
uses: marocchino/sticky-pull-request-comment@d4d6b0936434b21bc8345ad45a440c5f7d2c40ff #v3.0.3
with:
header: ${{ env.COMMENT_HEADER }}
hide: true
hide_classify: "OUTDATED"
- name: Add comment
if: ${{ hashFiles( env.CI_COMMENT_FILE ) != '' }}
uses: marocchino/sticky-pull-request-comment@d4d6b0936434b21bc8345ad45a440c5f7d2c40ff #v3.0.3
with:
header: ${{ env.COMMENT_HEADER }}
path: ${{ env.CI_COMMENT_FILE }}
@@ -1,18 +0,0 @@
name: Add to OSS board
permissions:
contents: read
on:
issues:
types:
- opened
- reopened
- transferred
- labeled
jobs:
run:
uses: "anchore/workflows/.github/workflows/oss-project-board-add.yaml@main"
secrets:
token: ${{ secrets.OSS_PROJECT_GH_TOKEN }}
+23 -108
View File
@@ -1,7 +1,11 @@
name: "Release"
permissions:
contents: read
permissions: {}
# there should never be two releases in progress at the same time
concurrency:
group: release
cancel-in-progress: false
on:
workflow_dispatch:
@@ -19,115 +23,26 @@ on:
- "install-script-only"
jobs:
quality-gate:
environment: release
version-available:
if: ${{ github.event.inputs.phase == 'all' }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
persist-credentials: false
uses: anchore/workflows/.github/workflows/check-version-available.yaml@8b2b1caf40e03933c6807e03b99e883e2ceb5ac8 # v0.4.0
with:
version: ${{ github.event.inputs.version }}
- name: Bootstrap environment
uses: ./.github/actions/bootstrap
- name: Validate Apple notarization credentials
run: .tool/quill submission list
env:
QUILL_NOTARY_ISSUER: ${{ secrets.APPLE_NOTARY_ISSUER }}
QUILL_NOTARY_KEY_ID: ${{ secrets.APPLE_NOTARY_KEY_ID }}
QUILL_NOTARY_KEY: ${{ secrets.APPLE_NOTARY_KEY }}
- name: Check if running on main
if: github.ref != 'refs/heads/main'
# we are using the following flag when running `cosign blob-verify` for checksum signature verification:
# --certificate-identity-regexp "https://github.com/anchore/.github/workflows/release.yaml@refs/heads/main"
# if we are not on the main branch, the signature will not be verifiable since the suffix requires the main branch
# at the time of when the OIDC token was issued on the Github Actions runner.
run: echo "This can only be run on the main branch otherwise releases produced will not be verifiable with cosign" && exit 1
- name: Check if tag already exists
# note: this will fail if the tag already exists
run: |
[[ "$VERSION" == v* ]] || (echo "version '$VERSION' does not have a 'v' prefix" && exit 1)
git tag "$VERSION"
env:
VERSION: ${{ github.event.inputs.version }}
- name: Check static analysis results
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
id: static-analysis
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Static analysis"
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check unit test results
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
id: unit
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Unit tests"
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check integration test results
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
id: integration
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Integration tests"
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
id: acceptance-linux
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Acceptance tests (Linux)"
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
id: acceptance-mac
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Acceptance tests (Mac)"
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
id: cli-linux
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "CLI tests (Linux)"
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Quality gate
if: steps.static-analysis.outputs.conclusion != 'success' || steps.unit.outputs.conclusion != 'success' || steps.integration.outputs.conclusion != 'success' || steps.cli-linux.outputs.conclusion != 'success' || steps.acceptance-linux.outputs.conclusion != 'success' || steps.acceptance-mac.outputs.conclusion != 'success'
env:
STATIC_ANALYSIS_STATUS: ${{ steps.static-analysis.conclusion }}
UNIT_TEST_STATUS: ${{ steps.unit.outputs.conclusion }}
INTEGRATION_TEST_STATUS: ${{ steps.integration.outputs.conclusion }}
ACCEPTANCE_LINUX_STATUS: ${{ steps.acceptance-linux.outputs.conclusion }}
ACCEPTANCE_MAC_STATUS: ${{ steps.acceptance-mac.outputs.conclusion }}
CLI_LINUX_STATUS: ${{ steps.cli-linux.outputs.conclusion }}
run: |
echo "Static Analysis Status: $STATIC_ANALYSIS_STATUS"
echo "Unit Test Status: $UNIT_TEST_STATUS"
echo "Integration Test Status: $INTEGRATION_TEST_STATUS"
echo "Acceptance Test (Linux) Status: $ACCEPTANCE_LINUX_STATUS"
echo "Acceptance Test (Mac) Status: $ACCEPTANCE_MAC_STATUS"
echo "CLI Test (Linux) Status: $CLI_LINUX_STATUS"
false
check-gate:
if: ${{ github.event.inputs.phase == 'all' }}
permissions:
checks: read # required for getting the status of specific check names
uses: anchore/workflows/.github/workflows/check-gate.yaml@8b2b1caf40e03933c6807e03b99e883e2ceb5ac8 # v0.4.0
with:
# these are checks that should be run on pull-request and merges to main.
# we do NOT want to kick off a release if these have not been verified on main.
# Please see the validations.yaml workflow for the names that should be used here.
checks: '["Acceptance tests (Linux)", "Acceptance tests (Mac)", "Build snapshot artifacts", "CLI tests (Linux)", "Integration tests", "Static analysis", "Unit tests"]'
release:
needs: [ quality-gate ]
needs: [ check-gate, version-available ]
if: ${{ github.event.inputs.phase == 'all' }}
# runs-on.com: compute instances for parallel builds
# spot disabled: reliability for build workflows (used for releases too)
@@ -193,7 +108,7 @@ jobs:
artifact-name: sbom.spdx.json
- name: Notify Slack of new release
uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 #v3.0.1
uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c #v3.0.3
continue-on-error: true
with:
webhook: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
@@ -1,15 +0,0 @@
name: "Manage Awaiting Response Label"
on:
issue_comment:
types: [created]
jobs:
run:
permissions:
contents: read
issues: write
pull-requests: write
uses: "anchore/workflows/.github/workflows/remove-awaiting-response-label.yaml@main"
secrets:
token: ${{ secrets.OSS_PROJECT_GH_TOKEN }}
@@ -10,8 +10,7 @@ on:
- '.github/workflows/**'
- '.github/actions/**'
permissions:
contents: read
permissions: {}
jobs:
zizmor:
@@ -26,7 +25,7 @@ jobs:
persist-credentials: false
- name: "Run zizmor"
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
with:
# there is a pass/fail gate as a repo ruleset (if there is no ruleset configured then the action will pass by default)
advanced-security: true
+15 -2
View File
@@ -13,8 +13,7 @@ on:
branches:
- main
permissions:
contents: read
permissions: {}
jobs:
Static-Analysis:
@@ -25,6 +24,8 @@ jobs:
# s3-cache: faster actions cache
# tmpfs: faster io-intensive workflows
runs-on: &test-runner "runs-on=${{ github.run_id }}/cpu=4+8/ram=32+128/family=r5+r6+r7+r8+m4+m5+m6+m7+m8/spot=price-capacity-optimized/extras=s3-cache+tmpfs"
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
@@ -45,6 +46,8 @@ jobs:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "Unit tests"
runs-on: *test-runner
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
@@ -65,6 +68,8 @@ jobs:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "Integration tests"
runs-on: *test-runner
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
@@ -89,6 +94,8 @@ jobs:
# s3-cache: faster actions cache
# tmpfs: faster io-intensive workflows
runs-on: "runs-on=${{ github.run_id }}/cpu=16+32/ram=32+128/family=c5+c6+c7+c8/spot=false/extras=s3-cache+tmpfs"
permissions:
contents: read
steps:
# required for magic-cache from runs-on to function with artifact upload/download (see https://runs-on.com/caching/magic-cache/#actionsupload-artifact-compatibility)
- uses: runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0 # v2.1.0
@@ -120,6 +127,8 @@ jobs:
name: "Acceptance tests (Linux)"
needs: [Build-Snapshot-Artifacts]
runs-on: *test-runner
permissions:
contents: read
steps:
# required for magic-cache from runs-on to function with artifact upload/download (see https://runs-on.com/caching/magic-cache/#actionsupload-artifact-compatibility)
- uses: runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0 # v2.1.0
@@ -162,6 +171,8 @@ jobs:
needs: [Build-Snapshot-Artifacts]
# note: macos runners aren't supported yet for runs-on managed runners.
runs-on: macos-latest
permissions:
contents: read
steps:
- name: Install Cosign
uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1
@@ -197,6 +208,8 @@ jobs:
name: "CLI tests (Linux)"
needs: [Build-Snapshot-Artifacts]
runs-on: *test-runner
permissions:
contents: read
steps:
# required for magic-cache from runs-on to function with artifact upload/download (see https://runs-on.com/caching/magic-cache/#actionsupload-artifact-compatibility)
- uses: runs-on/action@742bf56072eb4845a0f94b3394673e4903c90ff0 # v2.1.0
+55 -1
View File
@@ -14,7 +14,7 @@ builds:
dir: ./cmd/syft
binary: syft
goos: [linux]
goarch: [amd64, arm64, ppc64le, s390x]
goarch: [amd64, arm64, ppc64le, riscv64, s390x]
mod_timestamp: &build-timestamp '{{ .CommitTimestamp }}'
ldflags: &build-ldflags |
-w
@@ -114,6 +114,20 @@ dockers:
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-riscv64
- ghcr.io/anchore/syft:{{.Tag}}-riscv64
goarch: riscv64
dockerfile: Dockerfile
use: buildx
build_flag_templates:
- "--platform=linux/riscv64"
- "--build-arg=DEBIAN_VERSION=13"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-s390x
- ghcr.io/anchore/syft:{{.Tag}}-s390x
@@ -167,6 +181,20 @@ dockers:
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-nonroot-riscv64
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-riscv64
goarch: riscv64
dockerfile: Dockerfile.nonroot
use: buildx
build_flag_templates:
- "--platform=linux/riscv64"
- "--build-arg=DEBIAN_VERSION=13"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-nonroot-s390x
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-s390x
@@ -220,6 +248,20 @@ dockers:
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-debug-riscv64
- ghcr.io/anchore/syft:{{.Tag}}-debug-riscv64
goarch: riscv64
dockerfile: Dockerfile.debug
use: buildx
build_flag_templates:
- "--platform=linux/riscv64"
- "--build-arg=DEBIAN_VERSION=13"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- anchore/syft:{{.Tag}}-debug-s390x
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
@@ -239,6 +281,7 @@ docker_manifests:
- anchore/syft:{{.Tag}}-amd64
- anchore/syft:{{.Tag}}-arm64v8
- anchore/syft:{{.Tag}}-ppc64le
- anchore/syft:{{.Tag}}-riscv64
- anchore/syft:{{.Tag}}-s390x
- name_template: ghcr.io/anchore/syft:latest
@@ -246,6 +289,7 @@ docker_manifests:
- ghcr.io/anchore/syft:{{.Tag}}-amd64
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-riscv64
- ghcr.io/anchore/syft:{{.Tag}}-s390x
- name_template: anchore/syft:{{.Tag}}
@@ -253,6 +297,7 @@ docker_manifests:
- anchore/syft:{{.Tag}}-amd64
- anchore/syft:{{.Tag}}-arm64v8
- anchore/syft:{{.Tag}}-ppc64le
- anchore/syft:{{.Tag}}-riscv64
- anchore/syft:{{.Tag}}-s390x
- name_template: ghcr.io/anchore/syft:{{.Tag}}
@@ -260,6 +305,7 @@ docker_manifests:
- ghcr.io/anchore/syft:{{.Tag}}-amd64
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-riscv64
- ghcr.io/anchore/syft:{{.Tag}}-s390x
# nonroot images...
@@ -268,6 +314,7 @@ docker_manifests:
- anchore/syft:{{.Tag}}-nonroot-amd64
- anchore/syft:{{.Tag}}-nonroot-arm64v8
- anchore/syft:{{.Tag}}-nonroot-ppc64le
- anchore/syft:{{.Tag}}-nonroot-riscv64
- anchore/syft:{{.Tag}}-nonroot-s390x
- name_template: ghcr.io/anchore/syft:nonroot
@@ -275,6 +322,7 @@ docker_manifests:
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-amd64
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-riscv64
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-s390x
- name_template: anchore/syft:{{.Tag}}-nonroot
@@ -282,6 +330,7 @@ docker_manifests:
- anchore/syft:{{.Tag}}-nonroot-amd64
- anchore/syft:{{.Tag}}-nonroot-arm64v8
- anchore/syft:{{.Tag}}-nonroot-ppc64le
- anchore/syft:{{.Tag}}-nonroot-riscv64
- anchore/syft:{{.Tag}}-nonroot-s390x
- name_template: ghcr.io/anchore/syft:{{.Tag}}-nonroot
@@ -289,6 +338,7 @@ docker_manifests:
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-amd64
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-riscv64
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-s390x
# debug images...
@@ -297,6 +347,7 @@ docker_manifests:
- anchore/syft:{{.Tag}}-debug-amd64
- anchore/syft:{{.Tag}}-debug-arm64v8
- anchore/syft:{{.Tag}}-debug-ppc64le
- anchore/syft:{{.Tag}}-debug-riscv64
- anchore/syft:{{.Tag}}-debug-s390x
- name_template: ghcr.io/anchore/syft:debug
@@ -304,6 +355,7 @@ docker_manifests:
- ghcr.io/anchore/syft:{{.Tag}}-debug-amd64
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-debug-riscv64
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
- name_template: anchore/syft:{{.Tag}}-debug
@@ -311,6 +363,7 @@ docker_manifests:
- anchore/syft:{{.Tag}}-debug-amd64
- anchore/syft:{{.Tag}}-debug-arm64v8
- anchore/syft:{{.Tag}}-debug-ppc64le
- anchore/syft:{{.Tag}}-debug-riscv64
- anchore/syft:{{.Tag}}-debug-s390x
- name_template: ghcr.io/anchore/syft:{{.Tag}}-debug
@@ -318,6 +371,7 @@ docker_manifests:
- ghcr.io/anchore/syft:{{.Tag}}-debug-amd64
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
- ghcr.io/anchore/syft:{{.Tag}}-debug-riscv64
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
sboms:
+2 -1
View File
@@ -1,4 +1,5 @@
FROM gcr.io/distroless/static-debian12:latest AS build
ARG DEBIAN_VERSION=12
FROM gcr.io/distroless/static-debian${DEBIAN_VERSION}:latest AS build
FROM scratch
# needed for version check HTTPS request
+2 -1
View File
@@ -1,4 +1,5 @@
FROM gcr.io/distroless/static-debian12:debug-nonroot
ARG DEBIAN_VERSION=12
FROM gcr.io/distroless/static-debian${DEBIAN_VERSION}:debug-nonroot
# create the /tmp dir, which is needed for image content cache
WORKDIR /tmp
+2 -1
View File
@@ -1,4 +1,5 @@
FROM gcr.io/distroless/static-debian12:nonroot
ARG DEBIAN_VERSION=12
FROM gcr.io/distroless/static-debian${DEBIAN_VERSION}:nonroot
# create the /tmp dir, which is needed for image content cache
WORKDIR /tmp
+167 -172
View File
@@ -9,6 +9,7 @@ require (
github.com/Masterminds/sprig/v3 v3.3.0
github.com/OneOfOne/xxhash v1.2.8
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/acobaugh/osrelease v0.1.0
github.com/adrg/xdg v0.5.3
github.com/anchore/bubbly v0.2.0
github.com/anchore/clio v0.1.0
@@ -22,10 +23,12 @@ require (
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/packageurl-go v0.2.0
github.com/anchore/stereoscope v0.1.23
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
github.com/aquasecurity/go-pep440-version v0.0.1
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/bmatcuk/doublestar/v4 v4.10.0
github.com/cespare/xxhash/v2 v2.3.0
github.com/charmbracelet/bubbles v1.0.0
github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/lipgloss v1.1.0
@@ -38,16 +41,18 @@ require (
github.com/facebookincubator/nvdtools v0.1.5
github.com/github/go-spdx/v2 v2.4.0
github.com/gkampitakis/go-snaps v0.5.21
github.com/go-git/go-billy/v5 v5.8.0
github.com/go-git/go-git/v5 v5.18.0
github.com/go-git/go-billy/v5 v5.9.0
github.com/go-git/go-git/v5 v5.19.0
github.com/go-test/deep v1.1.1
github.com/go-viper/mapstructure/v2 v2.5.0
github.com/goccy/go-yaml v1.19.2
github.com/gohugoio/hashstructure v0.6.0
github.com/google/go-cmp v0.7.0
github.com/google/go-containerregistry v0.21.5
github.com/google/licensecheck v0.3.1
github.com/google/uuid v1.6.0
github.com/gookit/color v1.6.0
github.com/gpustack/gguf-parser-go v0.24.0
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-getter v1.8.6
github.com/hashicorp/go-multierror v1.1.1
@@ -57,6 +62,7 @@ require (
github.com/jedib0t/go-pretty/v6 v6.7.8
github.com/jinzhu/copier v0.4.0
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
github.com/klauspost/compress v1.18.5
github.com/magiconair/properties v1.8.10
github.com/mholt/archives v0.1.5
github.com/moby/sys/mountinfo v0.7.2
@@ -77,209 +83,52 @@ require (
github.com/spf13/afero v1.15.0
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.11.1
github.com/ulikunitz/xz v0.5.15
github.com/vbatts/go-mtree v0.7.0
github.com/vifraa/gopom v1.0.0
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651
github.com/wagoodman/go-progress v0.0.0-20260303201901-10176f79b2c0
github.com/wk8/go-ordered-map/v2 v2.1.8
github.com/xeipuuv/gojsonschema v1.2.0
github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1
go.uber.org/goleak v1.3.0
go.yaml.in/yaml/v3 v3.0.4
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f
golang.org/x/mod v0.35.0
golang.org/x/net v0.53.0
golang.org/x/time v0.15.0
golang.org/x/tools v0.44.0
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.46.2
)
require (
cel.dev/expr v0.25.1 // indirect
cloud.google.com/go v0.123.0 // indirect
cloud.google.com/go/auth v0.18.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
cloud.google.com/go/iam v1.5.3 // indirect
cloud.google.com/go/monitoring v1.24.3 // indirect
cloud.google.com/go/storage v1.61.3 // indirect
cyphar.com/go-pathrs v0.2.1 // indirect
dario.cat/mergo v1.0.2 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/Microsoft/hcsshim v0.14.0-rc.1 // indirect
github.com/ProtonMail/go-crypto v1.4.0 // indirect
github.com/STARRY-S/zip v0.2.3 // indirect
github.com/agext/levenshtein v1.2.1 // indirect; indirectt
github.com/agext/levenshtein v1.2.1 // indirect
github.com/anchore/go-lzo v0.1.0 // indirect
github.com/anchore/go-struct-converter v0.1.0 // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/aquasecurity/go-version v0.0.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bodgit/plumbing v1.3.0 // indirect
github.com/bodgit/sevenzip v1.6.1 // indirect
github.com/bodgit/windows v1.0.1 // indirect
github.com/charmbracelet/colorprofile v0.4.1 // indirect
github.com/charmbracelet/harmonica v0.2.0 // indirect
github.com/charmbracelet/x/ansi v0.11.6 // indirect
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
github.com/charmbracelet/x/term v0.2.2 // indirect
github.com/cloudflare/circl v1.6.3 // indirect
github.com/containerd/containerd/api v1.10.0 // indirect
github.com/containerd/continuity v0.4.5 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v1.0.0-rc.4 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
github.com/containerd/typeurl/v2 v2.2.3 // indirect
github.com/cyphar/filepath-securejoin v0.6.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/cli v29.4.0+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.5 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/fgprof v0.9.5 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/gkampitakis/ciinfo v0.3.2 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-restruct/restruct v1.2.0-alpha // indirect
github.com/goccy/go-yaml v1.19.2
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.14 // indirect
github.com/googleapis/gax-go/v2 v2.17.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-version v1.8.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.18.5 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/maruel/natural v1.1.1 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 // indirect
github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mikelolasagasti/xz v1.0.1 // indirect
github.com/minio/minlz v1.0.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // 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.6.0 // indirect
github.com/moby/sys/signal v0.7.1 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runtime-spec v1.3.0 // indirect
github.com/opencontainers/selinux v1.13.1 // indirect
github.com/pborman/indent v1.2.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/profile v1.7.0 // indirect
github.com/pkg/xattr v0.4.9 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sahilm/fuzzy v0.1.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/sorairolake/lzip-go v0.3.8 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/viper v1.21.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/sylabs/sif/v2 v2.24.0 // indirect
github.com/sylabs/squashfs v1.0.6 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/ulikunitz/xz v0.5.15
github.com/vbatts/tar-split v0.12.2 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/zclconf/go-cty v1.16.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.43.0 // indirect
go.opentelemetry.io/otel/metric v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/crypto v0.50.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/term v0.42.0 // indirect
golang.org/x/text v0.36.0 // indirect
golang.org/x/time v0.15.0
golang.org/x/tools v0.44.0
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/api v0.271.0 // indirect
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
google.golang.org/grpc v1.79.3 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1
modernc.org/libc v1.70.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)
require (
github.com/acobaugh/osrelease v0.1.0
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
github.com/cespare/xxhash/v2 v2.3.0
github.com/gpustack/gguf-parser-go v0.24.0
github.com/wk8/go-ordered-map/v2 v2.1.8
)
require (
cel.dev/expr v0.25.1 // indirect
cloud.google.com/go/monitoring v1.24.3 // indirect
cyphar.com/go-pathrs v0.2.1 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.41.5 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect
github.com/aws/aws-sdk-go-v2/config v1.32.12 // indirect
@@ -299,36 +148,182 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 // indirect
github.com/aws/smithy-go v1.24.2 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bodgit/plumbing v1.3.0 // indirect
github.com/bodgit/sevenzip v1.6.1 // indirect
github.com/bodgit/windows v1.0.1 // indirect
github.com/buger/jsonparser v1.1.2 // indirect
github.com/charmbracelet/colorprofile v0.4.1 // indirect
github.com/charmbracelet/harmonica v0.2.0 // indirect
github.com/charmbracelet/x/ansi v0.11.6 // indirect
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
github.com/charmbracelet/x/term v0.2.2 // indirect
github.com/clipperhouse/displaywidth v0.10.0 // indirect
github.com/clipperhouse/uax29/v2 v2.6.0 // indirect
github.com/cloudflare/circl v1.6.3 // indirect
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect
github.com/containerd/cgroups/v3 v3.1.2 // indirect
github.com/containerd/containerd/api v1.10.0 // indirect
github.com/containerd/containerd/v2 v2.2.2 // indirect
github.com/containerd/continuity v0.4.5 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v1.0.0-rc.4 // indirect
github.com/containerd/plugin v1.0.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
github.com/containerd/typeurl/v2 v2.2.3 // indirect
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/cli v29.4.0+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.5 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/fgprof v0.9.5 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/gkampitakis/ciinfo v0.3.2 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-restruct/restruct v1.2.0-alpha // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.14 // indirect
github.com/googleapis/gax-go/v2 v2.17.0 // indirect
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.72 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-version v1.8.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/henvic/httpretty v0.1.4 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/maruel/natural v1.1.1 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 // indirect
github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mikelolasagasti/xz v1.0.1 // indirect
github.com/minio/minlz v1.0.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // 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/moby/api v1.54.1 // indirect
github.com/moby/moby/client v0.4.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/signal v0.7.1 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
github.com/olekukonko/errors v1.2.0 // indirect
github.com/olekukonko/ll v0.1.6 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runtime-spec v1.3.0 // indirect
github.com/opencontainers/selinux v1.13.1 // indirect
github.com/pborman/indent v1.2.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pjbgf/sha1cd v0.6.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/profile v1.7.0 // indirect
github.com/pkg/xattr v0.4.9 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sahilm/fuzzy v0.1.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/smallnest/ringbuffer v0.0.0-20241116012123-461381446e3d // indirect
github.com/sorairolake/lzip-go v0.3.8 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/viper v1.21.0 // indirect
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/sylabs/sif/v2 v2.24.0 // indirect
github.com/sylabs/squashfs v1.0.6 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/vbatts/tar-split v0.12.2 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/zclconf/go-cty v1.16.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.43.0 // indirect
go.opentelemetry.io/otel/metric v1.43.0 // indirect
go.opentelemetry.io/otel/sdk v1.43.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/crypto v0.50.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/term v0.42.0 // indirect
golang.org/x/text v0.36.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
gonum.org/v1/gonum v0.16.0 // indirect
google.golang.org/api v0.271.0 // indirect
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
google.golang.org/grpc v1.79.3 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
modernc.org/libc v1.70.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)
retract (
+12 -10
View File
@@ -325,8 +325,8 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.6.0 h1:BtGB77njd6SVO6VztOHfPxKitJvd/VPT+OFBFMOi1Is=
github.com/cyphar/filepath-securejoin v0.6.0/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo=
github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -420,12 +420,12 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
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.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0=
github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=
github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA=
github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw=
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.18.0 h1:O831KI+0PR51hM2kep6T8k+w0/LIAD490gvqMCvL5hM=
github.com/go-git/go-git/v5 v5.18.0/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=
github.com/go-git/go-git/v5 v5.19.0 h1:+WkVUQZSy/F1Gb13udrMKjIM2PrzsNfDKFSfo5tkMtc=
github.com/go-git/go-git/v5 v5.19.0/go.mod h1:Pb1v0c7/g8aGQJwx9Us09W85yGoyvSwuhEGMH7zjDKQ=
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=
@@ -649,6 +649,8 @@ github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -790,8 +792,8 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU=
github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -1048,8 +1050,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+1
View File
@@ -154,6 +154,7 @@ uname_arch_check() (
mipsle) return 0 ;;
mips64) return 0 ;;
mips64le) return 0 ;;
riscv64) return 0 ;;
s390x) return 0 ;;
amd64p32) return 0 ;;
esac
@@ -96,6 +96,20 @@ var binaryClassifierOverrides = map[string][]binaryClassifierOverride{
CPEs: singleCPE("cpe:2.3:a:oracle:jdk:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
"openssl-binary": {
{
Class: "openssl-binary-aws-lc",
Package: "aws-lc",
PURL: mustPURL("pkg:generic/aws-lc@version"),
CPEs: singleCPE("cpe:2.3:a:amazon:aws_libcrypto:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "openssl-binary",
Package: "openssl",
PURL: mustPURL("pkg:generic/openssl@version"),
CPEs: singleCPE("cpe:2.3:a:openssl:openssl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
},
}
func mustPURL(purl string) string {
+13 -1
View File
@@ -12,8 +12,20 @@ const perFileReadLimit = 2 * GB
// protect against decompression bomb attacks.
func safeCopy(writer io.Writer, reader io.Reader) error {
numBytes, err := io.Copy(writer, io.LimitReader(reader, perFileReadLimit))
if numBytes >= perFileReadLimit || errors.Is(err, io.EOF) {
if numBytes >= perFileReadLimit {
return fmt.Errorf("zip read limit hit (potential decompression bomb attack)")
}
// Propagate decompression / read errors up to the caller. io.Copy
// on the happy path returns (n, nil); the only way err is non-nil
// here is that the underlying reader surfaced a real failure
// ("flate: corrupt input before offset X" on a mangled ZIP entry,
// a network-backed reader erroring mid-stream, etc.). The previous
// implementation dropped that error and the caller stored a
// partial / empty buffer as a "successful" extract, which silently
// downgraded Java cataloger output and caused SBOM scanners to
// miss known CVEs (#4806).
if err != nil && !errors.Is(err, io.EOF) {
return fmt.Errorf("failed to read archive entry: %w", err)
}
return nil
}
+64
View File
@@ -0,0 +1,64 @@
package file
import (
"bytes"
"errors"
"io"
"strings"
"testing"
)
// errReader returns a deterministic non-EOF error after emitting some
// bytes, mimicking what compress/flate does when it hits a corrupt
// stream mid-entry.
type errReader struct {
data []byte
err error
off int
}
func (r *errReader) Read(p []byte) (int, error) {
if r.off >= len(r.data) {
return 0, r.err
}
n := copy(p, r.data[r.off:])
r.off += n
return n, nil
}
func TestSafeCopy(t *testing.T) {
t.Run("clean copy returns nil", func(t *testing.T) {
var buf bytes.Buffer
if err := safeCopy(&buf, strings.NewReader("hello")); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := buf.String(); got != "hello" {
t.Fatalf("unexpected buffer contents: %q", got)
}
})
t.Run("propagates decompression error", func(t *testing.T) {
// #4806: safeCopy used to drop non-EOF errors, so the caller
// would persist a partial buffer as a successful extract and
// downstream catalogers silently read empty manifests.
sentinel := errors.New("flate: corrupt input before offset 42")
var buf bytes.Buffer
err := safeCopy(&buf, &errReader{data: []byte("partial"), err: sentinel})
if err == nil {
t.Fatalf("expected error to be returned, got nil")
}
if !errors.Is(err, sentinel) {
t.Fatalf("error does not wrap sentinel: %v", err)
}
})
t.Run("EOF is not treated as an error", func(t *testing.T) {
// The old code had a dead io.EOF branch that labelled clean
// reads as decompression bombs; keep the happy path clean.
var buf bytes.Buffer
err := safeCopy(&buf, io.LimitReader(strings.NewReader("abc"), 3))
if err != nil {
t.Fatalf("unexpected error on clean copy: %v", err)
}
})
}
+1
View File
@@ -5132,6 +5132,7 @@
"armv9-a",
"armv9-m",
"s390x",
"riscv64",
"ppc64",
"ppc64le",
"other",
+1
View File
@@ -6471,6 +6471,7 @@ limitations under the License.
<xs:enumeration value="armv9-a"/>
<xs:enumeration value="armv9-m"/>
<xs:enumeration value="s390x"/>
<xs:enumeration value="riscv64"/>
<xs:enumeration value="ppc64"/>
<xs:enumeration value="ppc64le"/>
<xs:enumeration value="other"/>
@@ -427,6 +427,17 @@ catalogers:
criteria:
- '**/openssl'
packages:
- class: openssl-binary
name: ""
purl: pkg:/
cpes: []
type: BinaryPkg
- class: openssl-binary-aws-lc
name: aws-lc
purl: pkg:generic/aws-lc
cpes:
- cpe:2.3:a:amazon:aws_libcrypto:*:*:*:*:*:*:*:*
type: BinaryPkg
- class: openssl-binary
name: openssl
purl: pkg:generic/openssl
@@ -684,6 +695,16 @@ catalogers:
cpes:
- cpe:2.3:a:mongodb:mongodb:*:*:*:*:*:*:*:*
type: BinaryPkg
- method: glob
criteria:
- '**/nginx-ingress-controller'
packages:
- class: ingress-nginx-binary
name: nginx-ingress-controller
purl: pkg:generic/nginx-ingress-controller
cpes:
- cpe:2.3:a:kubernetes:ingress-nginx:*:*:*:*:*:*:*:*
type: BinaryPkg
- method: glob
criteria:
- '**/java'
@@ -1485,6 +1485,17 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
Metadata: metadata("openssl-binary"),
},
},
{
logicalFixture: "aws-lc/1.69.0/linux-amd64",
expected: pkg.Package{
Name: "aws-lc",
Version: "1.69.0",
Type: "binary",
PURL: "pkg:generic/aws-lc@1.69.0",
Locations: locations("openssl"),
Metadata: metadata("openssl-binary-aws-lc"),
},
},
{
logicalFixture: "openldap/2.6.10/linux-amd64",
expected: pkg.Package{
@@ -1754,6 +1765,25 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
},
},
},
{
// release-candidate elixir image — pre-fix the matchers stripped the
// "-rc.1" suffix from the elixir-library result and missed the
// elixir-binary entirely (#4819).
logicalFixture: "elixir/1.12.0-rc.1/linux-amd64",
expected: pkg.Package{
Name: "elixir",
Version: "1.12.0-rc.1",
Type: "binary",
PURL: "pkg:generic/elixir@1.12.0-rc.1",
Locations: locations("elixir", "lib/elixir/ebin/elixir.app"),
Metadata: pkg.BinarySignature{
Matches: []pkg.ClassifierMatch{
match("elixir-binary", "elixir"),
match("elixir-library", "lib/elixir/ebin/elixir.app"),
},
},
},
},
{
logicalFixture: "istio_pilot-discovery/1.29.0-alpha.0/linux-amd64",
expected: pkg.Package{
@@ -2227,6 +2257,105 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
Metadata: metadata("envoy-binary"),
},
},
{
logicalFixture: "nginx-ingress-controller/1.15.1/linux-amd64",
expected: pkg.Package{
Name: "nginx-ingress-controller",
Version: "1.15.1",
Type: "binary",
PURL: "pkg:generic/nginx-ingress-controller@1.15.1",
Locations: locations("nginx-ingress-controller"),
Metadata: metadata("ingress-nginx-binary"),
},
},
{
logicalFixture: "nginx-ingress-controller/1.11.8/linux-amd64",
expected: pkg.Package{
Name: "nginx-ingress-controller",
Version: "1.11.8",
Type: "binary",
PURL: "pkg:generic/nginx-ingress-controller@1.11.8",
Locations: locations("nginx-ingress-controller"),
Metadata: metadata("ingress-nginx-binary"),
},
},
{
logicalFixture: "nginx-ingress-controller/1.9.6/linux-amd64",
expected: pkg.Package{
Name: "nginx-ingress-controller",
Version: "1.9.6",
Type: "binary",
PURL: "pkg:generic/nginx-ingress-controller@1.9.6",
Locations: locations("nginx-ingress-controller"),
Metadata: metadata("ingress-nginx-binary"),
},
},
{
logicalFixture: "nginx-ingress-controller/1.7.1/linux-amd64",
expected: pkg.Package{
Name: "nginx-ingress-controller",
Version: "1.7.1",
Type: "binary",
PURL: "pkg:generic/nginx-ingress-controller@1.7.1",
Locations: locations("nginx-ingress-controller"),
Metadata: metadata("ingress-nginx-binary"),
},
},
{
logicalFixture: "nginx-ingress-controller/1.12.0-beta.0/linux-amd64",
expected: pkg.Package{
Name: "nginx-ingress-controller",
Version: "1.12.0-beta.0",
Type: "binary",
PURL: "pkg:generic/nginx-ingress-controller@1.12.0-beta.0",
Locations: locations("nginx-ingress-controller"),
Metadata: metadata("ingress-nginx-binary"),
},
},
{
logicalFixture: "nginx-ingress-controller/1.2.0-beta.1/linux-amd64",
expected: pkg.Package{
Name: "nginx-ingress-controller",
Version: "1.2.0-beta.1",
Type: "binary",
PURL: "pkg:generic/nginx-ingress-controller@1.2.0-beta.1",
Locations: locations("nginx-ingress-controller"),
Metadata: metadata("ingress-nginx-binary"),
},
},
{
logicalFixture: "nginx-ingress-controller/1.0.0-alpha.2/linux-amd64",
expected: pkg.Package{
Name: "nginx-ingress-controller",
Version: "1.0.0-alpha.2",
Type: "binary",
PURL: "pkg:generic/nginx-ingress-controller@1.0.0-alpha.2",
Locations: locations("nginx-ingress-controller"),
Metadata: metadata("ingress-nginx-binary"),
},
},
{
logicalFixture: "nginx-ingress-controller/0.34.0/linux-amd64",
expected: pkg.Package{
Name: "nginx-ingress-controller",
Version: "0.34.0",
Type: "binary",
PURL: "pkg:generic/nginx-ingress-controller@0.34.0",
Locations: locations("nginx-ingress-controller"),
Metadata: metadata("ingress-nginx-binary"),
},
},
{
logicalFixture: "nginx-ingress-controller/0.33.0/linux-amd64",
expected: pkg.Package{
Name: "nginx-ingress-controller",
Version: "0.33.0",
Type: "binary",
PURL: "pkg:generic/nginx-ingress-controller@0.33.0",
Locations: locations("nginx-ingress-controller"),
Metadata: metadata("ingress-nginx-binary"),
},
},
}
for _, test := range tests {
+64 -17
View File
@@ -106,13 +106,19 @@ func DefaultClassifiers() []binutils.Classifier {
{
Class: "redis-binary",
FileGlob: "**/redis-server",
EvidenceMatcher: binutils.MatchAny(
// matches most recent versions of redis (~v7), e.g. "7.0.14buildkitsandbox-1702957741000000000"
m.FileContentsVersionMatcher(`[^\d](?P<version>\d+.\d+\.\d+)buildkitsandbox-\d+`),
// matches against older versions of redis (~v3 - v6), e.g. "4.0.11841ce7054bd9-1542359302000000000"
m.FileContentsVersionMatcher(`[^\d](?P<version>[0-9]+\.[0-9]+\.[0-9]+)\w{12}-\d+`),
// matches against older versions of redis (~v2), e.g. "Server started, Redis version 2.8.23"
m.FileContentsVersionMatcher(`Redis version (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
EvidenceMatcher: binutils.MatchAll(
// Negative Matchers to exclude valkey-server
binutils.MatchNone(
binutils.MatchPath("**/valkey-server"),
),
binutils.MatchAny(
// matches most recent versions of redis (~v7), e.g. "7.0.14buildkitsandbox-1702957741000000000"
m.FileContentsVersionMatcher(`[^\d](?P<version>\d+.\d+\.\d+)buildkitsandbox-\d+`),
// matches against older versions of redis (~v3 - v6), e.g. "4.0.11841ce7054bd9-1542359302000000000"
m.FileContentsVersionMatcher(`[^\d](?P<version>[0-9]+\.[0-9]+\.[0-9]+)\w{12}-\d+`),
// matches against older versions of redis (~v2), e.g. "Server started, Redis version 2.8.23"
m.FileContentsVersionMatcher(`Redis version (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
),
),
Package: "redis",
PURL: mustPURL("pkg:generic/redis@version"),
@@ -558,14 +564,29 @@ func DefaultClassifiers() []binutils.Classifier {
{
Class: "openssl-binary",
FileGlob: "**/openssl",
EvidenceMatcher: m.FileContentsVersionMatcher(
// [NUL]OpenSSL 3.1.4'
// [NUL]OpenSSL 1.1.1w'
`\x00OpenSSL (?P<version>[0-9]+\.[0-9]+\.[0-9]+([a-z]+|-alpha[0-9]|-beta[0-9]|-rc[0-9])?)`,
),
Package: "openssl",
PURL: mustPURL("pkg:generic/openssl@version"),
CPEs: singleCPE("cpe:2.3:a:openssl:openssl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
EvidenceMatcher: binutils.BranchingEvidenceMatcher([]binutils.Classifier{
{
Class: "openssl-binary-aws-lc",
EvidenceMatcher: m.FileContentsVersionMatcher(
// [NUL]OpenSSL 1.1.1 (compatible; AWS-LC 1.69.0)[NUL]
`AWS-LC (?P<version>[0-9]+\.[0-9]+\.[0-9]+)\)\x00`,
),
Package: "aws-lc",
PURL: mustPURL("pkg:generic/aws-lc@version"),
CPEs: singleCPE("cpe:2.3:a:amazon:aws_libcrypto:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "openssl-binary",
EvidenceMatcher: m.FileContentsVersionMatcher(
// [NUL]OpenSSL 3.1.4'
// [NUL]OpenSSL 1.1.1w'
`\x00OpenSSL (?P<version>[0-9]+\.[0-9]+\.[0-9]+([a-z]+|-alpha[0-9]|-beta[0-9]|-rc[0-9])?)`,
),
Package: "openssl",
PURL: mustPURL("pkg:generic/openssl@version"),
CPEs: singleCPE("cpe:2.3:a:openssl:openssl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
}...),
},
{
Class: "openldap-search-binary",
@@ -762,7 +783,9 @@ func DefaultClassifiers() []binutils.Classifier {
Class: "elixir-binary",
FileGlob: "**/elixir",
EvidenceMatcher: m.FileContentsVersionMatcher(
`(?m)ELIXIR_VERSION=(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
// Capture optional pre-release suffix (-rc.1, -alpha.0, -beta.2,
// etc.) so release-candidate elixir images (#4819) match.
`(?m)ELIXIR_VERSION=(?P<version>[0-9]+\.[0-9]+\.[0-9]+(?:-[a-z0-9]+(?:\.[0-9]+)?)?)`),
Package: "elixir",
PURL: mustPURL("pkg:generic/elixir@version"),
CPEs: []cpe.CPE{
@@ -773,7 +796,8 @@ func DefaultClassifiers() []binutils.Classifier {
Class: "elixir-library",
FileGlob: "**/elixir/ebin/elixir.app",
EvidenceMatcher: m.FileContentsVersionMatcher(
`(?m)\{vsn,"(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9]+)?)"\}`),
// Same pre-release extension as elixir-binary above.
`(?m)\{vsn,"(?P<version>[0-9]+\.[0-9]+\.[0-9]+(?:-[a-z0-9]+(?:\.[0-9]+)?)?)"\}`),
Package: "elixir",
PURL: mustPURL("pkg:generic/elixir@version"),
CPEs: singleCPE("cpe:2.3:a:elixir-lang:elixir:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
@@ -905,6 +929,29 @@ func DefaultClassifiers() []binutils.Classifier {
PURL: mustPURL("pkg:generic/mongodb@version"),
CPEs: singleCPE("cpe:2.3:a:mongodb:mongodb:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
{
Class: "ingress-nginx-binary",
FileGlob: "**/nginx-ingress-controller",
EvidenceMatcher: binutils.MatchAny(
// [NUL][NUL]v1.15.1[NUL][NUL]@e[ETX][NUL][NUL][NUL][NUL]go1.26.1[NUL][NUL][NUL]
// �v1.15.1[NUL][NUL]�z[ETX][NUL][NUL][NUL][NUL]go1.24.4[NUL][NUL][NUL]
m.FileContentsVersionMatcher(`v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00+.{0,50}go[0-9]+\.[0-9]+(\-(alpha|beta)\.[0-9])?\.[0-9]+\x00+`),
// �Lv1.9.6[NUL][NUL]$a�c[SOH][NUL][NUL][NUL]
// [NUL][NUL]v0.34.0[NUL]......�$a�...[NUL]
m.FileContentsVersionMatcher(`v(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\-(alpha|beta)\.[0-9])?)\x00+.{0,800}\$a.{0,10}\x00+`),
// [NUL][NUL]v1.7.1[NUL][NUL][NUL]...S=v<y5...
// [NUL]0.33.0[NUL][NUL]...[NUL][NUL]...S=v<y5
m.FileContentsVersionMatcher(`\x00+v?(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\-(alpha|beta)\.[0-9])?)\x00+.{0,100}S=v<y5`),
// [NUL][NUL]go1.22.8[NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL]v1.12.0-beta.0[NUL][NUL]
m.FileContentsVersionMatcher(`\x00+go[0-9]+\.[0-9]+\.[0-9]+\x00+v(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\-(alpha|beta)\.[0-9])?)\x00+`),
// [NUL][NUL]v1.2.0-beta.1[NUL][NUL]
// [NUL][NUL]v1.0.0-alpha.2[NUL][NUL]
m.FileContentsVersionMatcher(`\x00+v(?P<version>[0-9]+\.[0-9]+\.[0-9]+\-(alpha|beta)\.[0-9])\x00+`),
),
Package: "nginx-ingress-controller",
PURL: mustPURL("pkg:generic/nginx-ingress-controller@version"),
CPEs: singleCPE("cpe:2.3:a:kubernetes:ingress-nginx:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
},
}
return append(classifiers, defaultJavaClassifiers()...)
@@ -0,0 +1,20 @@
#!/bin/sh
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: 2021 The Elixir Team
# SPDX-FileCopyrightText: 2012 Plataformatec
set -e
ELIXIR_VERSION=1.12.0-rc.1
if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then
cat <<USAGE >&2
Usage: $(basename "$0") [options] [.exs file] [data]
## General options
-e "COMMAND" Evaluates the given command (*)
-h, --help Prints this message (standalone)
-r "FILE" Requires the given files/patterns (*)
-S SCRIPT Finds and executes the given script in \$PATH
@@ -0,0 +1,19 @@
{application,elixir,
[{description,"elixir"},
{vsn,"1.12.0-rc.1"},
{modules,
['Elixir.Access','Elixir.Agent.Server','Elixir.Agent',
'Elixir.Application','Elixir.ArgumentError',
elixir_overridable,elixir_parser,elixir_quote,elixir_rewrite,
elixir_sup,elixir_tokenizer,elixir_utils,iex]},
{registered,[elixir_sup,elixir_config,elixir_code_server]},
{applications,[kernel,stdlib,compiler]},
{mod,{elixir,[]}},
{env,
[{ansi_syntax_colors,
[{atom,cyan},
{binary,default_color},
{operator,default_color}]},
{check_endianness,true},
{dbg_callback,{'Elixir.Macro',dbg,[]}},
{time_zone_database,'Elixir.Calendar.UTCOnlyTimeZoneDatabase'}]}]}.
+83 -2
View File
@@ -625,12 +625,14 @@ from-images:
paths:
- /usr/local/bin/redis-server
- version: 9.0.0
- name: valkey-server
version: 9.0.0
images:
- ref: valkey/valkey:9.0.0@sha256:42ea97850708540d4e05f6241cfbd241c1ba502e64d9a42efb2c2e277a8ca9d6
platform: linux/amd64
paths:
- /usr/local/bin/valkey-server
- /usr/local/bin/redis-server
- version: 2.9.0
images:
@@ -917,11 +919,19 @@ from-images:
- name: openssl
version: 1.1.1w
images:
- ref: openresty/openresty:1.25.3.1-2-alpine@sha256:b1cb45b1556801b8cb1bc29ea78faf2eaf67926a37b052dd070866e44d7df07a
- ref: openresty/openresty:1.25.3.1-2-alpine@sha256:6c24f25318e5ecf0c981bec584842af329552a538fe48a24ec25387374c652b2
platform: linux/arm64
paths:
- /usr/local/openresty/openssl/bin/openssl
- name: aws-lc
version: 1.69.0
images:
- ref: haproxytech/haproxy-alpine:3.3.8@sha256:ba237771cc7e734b4449829b09d107012c8d7578d77487b8453207e7ca851996
platform: linux/amd64
paths:
- /opt/aws-lc/bin/openssl
- name: openldap
version: 2.6.10
images:
@@ -1379,3 +1389,74 @@ from-images:
platform: linux/amd64
paths:
- /usr/local/bin/envoy
- version: 1.15.1
images:
- ref: registry.k8s.io/ingress-nginx/controller:v1.15.1@sha256:594ceea76b01c592858f803f9ff4d2cb40542cae2060410b2c95f75907d659e1
platform: linux/amd64
paths:
- /nginx-ingress-controller
- version: 1.11.8
images:
- ref: registry.k8s.io/ingress-nginx/controller:v1.11.8@sha256:695d79381ee6af00c7f5c9fd434f50851d7d32838ad5b2c507e416cf2084fc79
platform: linux/amd64
paths:
- /nginx-ingress-controller
- version: 1.9.6
images:
- ref: registry.k8s.io/ingress-nginx/controller:v1.9.6@sha256:1405cc613bd95b2c6edd8b2a152510ae91c7e62aea4698500d23b2145960ab9c
platform: linux/amd64
paths:
- /nginx-ingress-controller
- version: 1.8.4
images:
- ref: registry.k8s.io/ingress-nginx/controller:v1.8.4@sha256:8d8ddf32b83ca3e74bd5f66369fa60d85353e18ff55fa7691b321aa4716f5ba9
platform: linux/amd64
paths:
- /nginx-ingress-controller
- version: 1.7.1
images:
- ref: registry.k8s.io/ingress-nginx/controller:v1.7.1@sha256:7244b95ea47bddcb8267c1e625fb163fc183ef55448855e3ac52a7b260a60407
platform: linux/amd64
paths:
- /nginx-ingress-controller
- version: 1.12.0-beta.0
images:
- ref: registry.k8s.io/ingress-nginx/controller:v1.12.0-beta.0@sha256:9724476b928967173d501040631b23ba07f47073999e80e34b120e8db5f234d5
platform: linux/amd64
paths:
- /nginx-ingress-controller
- version: 1.2.0-beta.1
images:
- ref: k8s.gcr.io/ingress-nginx/controller:v1.2.0-beta.1@sha256:7059739637c30865f74cae403fffa55c2cb6d9779cd15654480dd0e4f850d536
platform: linux/amd64
paths:
- /nginx-ingress-controller
- version: 1.0.0-alpha.2
images:
- ref: k8s.gcr.io/ingress-nginx/controller:v1.0.0-alpha.2@sha256:04a0ad3a1279c2a58898e789eed767eafa138ee1e5b9b23a988c6e8485cf958d
platform: linux/amd64
paths:
- /nginx-ingress-controller
- version: 0.34.0
images:
- ref: k8s.gcr.io/ingress-nginx/controller:v0.34.0@sha256:5e0dcdc3ddb076f9ad988c624b8c459b53235ace26b9b18c192dedd3a038173c
platform: linux/amd64
paths:
- /nginx-ingress-controller
- version: 0.33.0
images:
- ref: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.33.0@sha256:ad8a1e9e44b4deb6ded8d677e9f0014178294e579d0710a48bca1e05838f2473
platform: linux/amd64
paths:
- /nginx-ingress-controller
+71 -48
View File
@@ -18,71 +18,60 @@ var (
licensePattern = regexp.MustCompile(`^License: (?P<license>\S*)`)
commonLicensePathPattern = regexp.MustCompile(`/usr/share/common-licenses/(?P<license>[0-9A-Za-z_.\-]+)`)
licenseAgreementHeadingPattern = regexp.MustCompile(`(?i)^\s*(?P<license>LICENSE AGREEMENT(?: FOR .+?)?)\s*$`)
formatHeaderPattern = regexp.MustCompile(`^Format:\s*https?://www\.debian\.org/doc/packaging-manuals/copyright-format/`)
)
// heading-detection states. Replaces licenseFirstSentenceAfterHeadingPattern,
// which only matched at the start of the file: a non-empty heading, a line
// of dashes, blank lines, then text up to the first period.
const (
expectHeading = iota
expectDashes
skipBlanks
captureLicense
headingDone // matched or impossible — stop checking
)
func parseLicensesFromCopyright(reader io.Reader) []string {
findings := strset.New()
scanner := bufio.NewScanner(reader)
// State machine replacing licenseFirstSentenceAfterHeadingPattern.
// That regex only matched at the start of the file: a non-empty heading,
// a line of dashes, blank lines, then text up to the first period.
const (
expectHeading = iota
expectDashes
skipBlanks
captureLicense
headingDone // matched or impossible — stop checking
)
// per the DEP-5 spec, machine-readable copyright files MUST have a
// Format field whose value is a URI for the specification. Only files
// with this header should be parsed as machine-readable.
// See: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
formatVerified := false
headingState := expectHeading
var licenseText strings.Builder
for scanner.Scan() {
line := scanner.Text()
// per-line regex checks (applied to every line)
if value := findLicenseClause(licensePattern, line); value != "" {
findings.Add(value)
}
if value := findLicenseClause(commonLicensePathPattern, line); value != "" {
findings.Add(value)
}
if value := findLicenseClause(licenseAgreementHeadingPattern, line); value != "" {
findings.Add(value)
if !formatVerified {
if strings.TrimSpace(line) == "" {
continue
}
if !formatHeaderPattern.MatchString(line) {
return nil
}
formatVerified = true
}
// multi-line heading detection (only at start of file)
switch headingState {
case expectHeading:
if strings.TrimSpace(line) != "" {
headingState = expectDashes
} else {
headingState = headingDone
}
case expectDashes:
trimmed := strings.TrimSpace(line)
if len(trimmed) > 0 && strings.Trim(trimmed, "-") == "" {
headingState = skipBlanks
} else {
headingState = headingDone
}
case skipBlanks:
if strings.TrimSpace(line) != "" {
headingState = captureLicense
licenseText.WriteString(line)
if value := extractUpToFirstPeriod(licenseText.String()); value != "" {
findings.Add(value)
headingState = headingDone
}
}
case captureLicense:
licenseText.WriteString(" ")
licenseText.WriteString(line)
if value := extractUpToFirstPeriod(licenseText.String()); value != "" {
for _, p := range []*regexp.Regexp{licensePattern, commonLicensePathPattern, licenseAgreementHeadingPattern} {
if value := findLicenseClause(p, line); value != "" {
findings.Add(value)
headingState = headingDone
}
}
var found string
headingState, found = advanceHeadingState(headingState, line, &licenseText)
if found != "" {
findings.Add(found)
}
}
if !formatVerified {
return nil
}
results := findings.List()
@@ -91,6 +80,40 @@ func parseLicensesFromCopyright(reader io.Reader) []string {
return results
}
func advanceHeadingState(state int, line string, licenseText *strings.Builder) (int, string) {
switch state {
case expectHeading:
if strings.TrimSpace(line) != "" {
return expectDashes, ""
}
return headingDone, ""
case expectDashes:
trimmed := strings.TrimSpace(line)
if len(trimmed) > 0 && strings.Trim(trimmed, "-") == "" {
return skipBlanks, ""
}
return headingDone, ""
case skipBlanks:
if strings.TrimSpace(line) == "" {
return state, ""
}
licenseText.WriteString(line)
if value := extractUpToFirstPeriod(licenseText.String()); value != "" {
return headingDone, value
}
return captureLicense, ""
case captureLicense:
licenseText.WriteString(" ")
licenseText.WriteString(line)
if value := extractUpToFirstPeriod(licenseText.String()); value != "" {
return headingDone, value
}
return state, ""
case headingDone:
}
return state, ""
}
// extractUpToFirstPeriod returns the license text up to the first period,
// processed through ensureIsSingleLicense, or "" if no period found yet.
func extractUpToFirstPeriod(s string) string {
@@ -2,6 +2,7 @@ package debian
import (
"os"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
@@ -14,13 +15,14 @@ func TestParseLicensesFromCopyright(t *testing.T) {
expected []string
}{
{
fixture: "testdata/copyright/libc6",
// note: there are other licenses in this file that are not matched --we don't do full text license identification yet
expected: []string{"GPL-2", "LGPL-2.1"},
// no Format header; not machine-readable, returns nil
fixture: "testdata/copyright/libc6",
expected: nil,
},
{
// no Format header; not machine-readable, returns nil
fixture: "testdata/copyright/trilicense",
expected: []string{"GPL-2", "LGPL-2.1", "MPL-1.1"},
expected: nil,
},
{
fixture: "testdata/copyright/liblzma5",
@@ -31,21 +33,25 @@ func TestParseLicensesFromCopyright(t *testing.T) {
expected: []string{"GPL-1", "GPL-2", "LGPL-2.1"},
},
{
fixture: "testdata/copyright/python",
// note: this should not capture #, Permission, This, see ... however it's not clear how to fix this (this is probably good enough)
expected: []string{"#", "Apache", "Apache-2", "Apache-2.0", "Expat", "GPL-2", "ISC", "LGPL-2.1+", "PSF-2", "Permission", "Python", "This", "see"},
// no Format header; not machine-readable, returns nil
// previously this captured nonsensical values like "#", "Permission", "This", "see"
fixture: "testdata/copyright/python",
expected: nil,
},
{
// no Format header; not machine-readable, returns nil
fixture: "testdata/copyright/cuda",
expected: []string{"NVIDIA Software License Agreement and CUDA Supplement to Software License Agreement"},
expected: nil,
},
{
// no Format header; not machine-readable, returns nil
fixture: "testdata/copyright/dev-kit",
expected: []string{"LICENSE AGREEMENT FOR NVIDIA SOFTWARE DEVELOPMENT KITS"},
expected: nil,
},
{
// no Format header; not machine-readable, returns nil
fixture: "testdata/copyright/microsoft",
expected: []string{"LICENSE AGREEMENT FOR MICROSOFT PRODUCTS"},
expected: nil,
},
}
@@ -63,3 +69,71 @@ func TestParseLicensesFromCopyright(t *testing.T) {
})
}
}
func TestParseLicensesFromCopyright_FormatHeader(t *testing.T) {
tests := []struct {
name string
content string
machineReadable bool
}{
{
name: "valid http Format header",
content: "Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\n",
machineReadable: true,
},
{
name: "valid https Format header",
content: "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\n",
machineReadable: true,
},
{
name: "blank lines before Format header",
content: "\n\nFormat: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\n",
machineReadable: true,
},
{
name: "no Format header",
content: "This is the Debian prepackaged version of foo.\n",
machineReadable: false,
},
{
name: "Format header is not first non-blank line",
content: "Some-Field: value\nFormat: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\n",
machineReadable: false,
},
{
name: "empty content",
content: "",
machineReadable: false,
},
{
name: "only blank lines",
content: "\n\n\n",
machineReadable: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := parseLicensesFromCopyright(strings.NewReader(test.content))
// parseLicensesFromCopyright returns nil for non-machine-readable
// files and a (possibly empty) slice otherwise.
if test.machineReadable {
require.NotNil(t, actual)
} else {
require.Nil(t, actual)
}
})
}
}
func TestParseLicensesFromCopyrightInline(t *testing.T) {
// verify that a file with License: fields but no Format header returns nil
content := `License: GPL-2
License: LGPL-2.1
`
actual := parseLicensesFromCopyright(strings.NewReader(content))
if actual != nil {
t.Errorf("expected nil for non-machine-readable file, got %v", actual)
}
}
+172 -168
View File
@@ -319,174 +319,174 @@ func TestCataloger(t *testing.T) {
net8AppExpectedBinarySelfContainedPkgs = append(net8AppExpectedBinarySelfContainedPkgs,
// include the runtime...
".NET Runtime @ 8,0,1425,11118 (/app/coreclr.dll)",
"Microsoft.CSharp @ 8.0.1425.11118 (/app/Microsoft.CSharp.dll)",
"Microsoft.VisualBasic @ 8.0.1425.11118 (/app/Microsoft.VisualBasic.dll)",
"Microsoft.CSharp @ 8.0.14 (/app/Microsoft.CSharp.dll)",
"Microsoft.VisualBasic @ 8.0.14 (/app/Microsoft.VisualBasic.dll)",
"Microsoft.VisualBasic.Core @ 13.0.1425.11118 (/app/Microsoft.VisualBasic.Core.dll)",
"Microsoft.Win32.Primitives @ 8.0.1425.11118 (/app/Microsoft.Win32.Primitives.dll)",
"Microsoft.Win32.Registry @ 8.0.1425.11118 (/app/Microsoft.Win32.Registry.dll)",
"System @ 8.0.1425.11118 (/app/System.dll)",
"System.AppContext @ 8.0.1425.11118 (/app/System.AppContext.dll)",
"System.Buffers @ 8.0.1425.11118 (/app/System.Buffers.dll)",
"System.Collections @ 8.0.1425.11118 (/app/System.Collections.dll)",
"System.Collections.Concurrent @ 8.0.1425.11118 (/app/System.Collections.Concurrent.dll)",
"System.Collections.Immutable @ 8.0.1425.11118 (/app/System.Collections.Immutable.dll)",
"System.Collections.NonGeneric @ 8.0.1425.11118 (/app/System.Collections.NonGeneric.dll)",
"System.Collections.Specialized @ 8.0.1425.11118 (/app/System.Collections.Specialized.dll)",
"System.ComponentModel @ 8.0.1425.11118 (/app/System.ComponentModel.dll)",
"System.ComponentModel.Annotations @ 8.0.1425.11118 (/app/System.ComponentModel.Annotations.dll)",
"System.ComponentModel.DataAnnotations @ 8.0.1425.11118 (/app/System.ComponentModel.DataAnnotations.dll)",
"System.ComponentModel.EventBasedAsync @ 8.0.1425.11118 (/app/System.ComponentModel.EventBasedAsync.dll)",
"System.ComponentModel.Primitives @ 8.0.1425.11118 (/app/System.ComponentModel.Primitives.dll)",
"System.ComponentModel.TypeConverter @ 8.0.1425.11118 (/app/System.ComponentModel.TypeConverter.dll)",
"System.Configuration @ 8.0.1425.11118 (/app/System.Configuration.dll)",
"System.Console @ 8.0.1425.11118 (/app/System.Console.dll)",
"System.Core @ 8.0.1425.11118 (/app/System.Core.dll)",
"System.Data @ 8.0.1425.11118 (/app/System.Data.dll)",
"System.Data.Common @ 8.0.1425.11118 (/app/System.Data.Common.dll)",
"System.Data.DataSetExtensions @ 8.0.1425.11118 (/app/System.Data.DataSetExtensions.dll)",
"System.Diagnostics.Contracts @ 8.0.1425.11118 (/app/System.Diagnostics.Contracts.dll)",
"System.Diagnostics.Debug @ 8.0.1425.11118 (/app/System.Diagnostics.Debug.dll)",
"System.Diagnostics.DiagnosticSource @ 8.0.1425.11118 (/app/System.Diagnostics.DiagnosticSource.dll)",
"System.Diagnostics.FileVersionInfo @ 8.0.1425.11118 (/app/System.Diagnostics.FileVersionInfo.dll)",
"System.Diagnostics.Process @ 8.0.1425.11118 (/app/System.Diagnostics.Process.dll)",
"System.Diagnostics.StackTrace @ 8.0.1425.11118 (/app/System.Diagnostics.StackTrace.dll)",
"System.Diagnostics.TextWriterTraceListener @ 8.0.1425.11118 (/app/System.Diagnostics.TextWriterTraceListener.dll)",
"System.Diagnostics.Tools @ 8.0.1425.11118 (/app/System.Diagnostics.Tools.dll)",
"System.Diagnostics.TraceSource @ 8.0.1425.11118 (/app/System.Diagnostics.TraceSource.dll)",
"System.Diagnostics.Tracing @ 8.0.1425.11118 (/app/System.Diagnostics.Tracing.dll)",
"System.Drawing @ 8.0.1425.11118 (/app/System.Drawing.dll)",
"System.Drawing.Primitives @ 8.0.1425.11118 (/app/System.Drawing.Primitives.dll)",
"System.Dynamic.Runtime @ 8.0.1425.11118 (/app/System.Dynamic.Runtime.dll)",
"System.Formats.Asn1 @ 8.0.1425.11118 (/app/System.Formats.Asn1.dll)",
"System.Formats.Tar @ 8.0.1425.11118 (/app/System.Formats.Tar.dll)",
"System.Globalization @ 8.0.1425.11118 (/app/System.Globalization.dll)",
"System.Globalization.Calendars @ 8.0.1425.11118 (/app/System.Globalization.Calendars.dll)",
"System.Globalization.Extensions @ 8.0.1425.11118 (/app/System.Globalization.Extensions.dll)",
"System.IO @ 8.0.1425.11118 (/app/System.IO.dll)",
"System.IO.Compression @ 8.0.1425.11118 (/app/System.IO.Compression.dll)",
"System.IO.Compression.Brotli @ 8.0.1425.11118 (/app/System.IO.Compression.Brotli.dll)",
"System.IO.Compression.FileSystem @ 8.0.1425.11118 (/app/System.IO.Compression.FileSystem.dll)",
"System.IO.Compression.ZipFile @ 8.0.1425.11118 (/app/System.IO.Compression.ZipFile.dll)",
"System.IO.FileSystem @ 8.0.1425.11118 (/app/System.IO.FileSystem.dll)",
"System.IO.FileSystem.AccessControl @ 8.0.1425.11118 (/app/System.IO.FileSystem.AccessControl.dll)",
"System.IO.FileSystem.DriveInfo @ 8.0.1425.11118 (/app/System.IO.FileSystem.DriveInfo.dll)",
"System.IO.FileSystem.Primitives @ 8.0.1425.11118 (/app/System.IO.FileSystem.Primitives.dll)",
"System.IO.FileSystem.Watcher @ 8.0.1425.11118 (/app/System.IO.FileSystem.Watcher.dll)",
"System.IO.IsolatedStorage @ 8.0.1425.11118 (/app/System.IO.IsolatedStorage.dll)",
"System.IO.MemoryMappedFiles @ 8.0.1425.11118 (/app/System.IO.MemoryMappedFiles.dll)",
"System.IO.Pipes @ 8.0.1425.11118 (/app/System.IO.Pipes.dll)",
"System.IO.Pipes.AccessControl @ 8.0.1425.11118 (/app/System.IO.Pipes.AccessControl.dll)",
"System.IO.UnmanagedMemoryStream @ 8.0.1425.11118 (/app/System.IO.UnmanagedMemoryStream.dll)",
"System.Linq @ 8.0.1425.11118 (/app/System.Linq.dll)",
"System.Linq.Expressions @ 8.0.1425.11118 (/app/System.Linq.Expressions.dll)",
"System.Linq.Parallel @ 8.0.1425.11118 (/app/System.Linq.Parallel.dll)",
"System.Linq.Queryable @ 8.0.1425.11118 (/app/System.Linq.Queryable.dll)",
"System.Memory @ 8.0.1425.11118 (/app/System.Memory.dll)",
"System.Net @ 8.0.1425.11118 (/app/System.Net.dll)",
"System.Net.Http @ 8.0.1425.11118 (/app/System.Net.Http.dll)",
"System.Net.Http.Json @ 8.0.1425.11118 (/app/System.Net.Http.Json.dll)",
"System.Net.HttpListener @ 8.0.1425.11118 (/app/System.Net.HttpListener.dll)",
"System.Net.Mail @ 8.0.1425.11118 (/app/System.Net.Mail.dll)",
"System.Net.NameResolution @ 8.0.1425.11118 (/app/System.Net.NameResolution.dll)",
"System.Net.NetworkInformation @ 8.0.1425.11118 (/app/System.Net.NetworkInformation.dll)",
"System.Net.Ping @ 8.0.1425.11118 (/app/System.Net.Ping.dll)",
"System.Net.Primitives @ 8.0.1425.11118 (/app/System.Net.Primitives.dll)",
"System.Net.Quic @ 8.0.1425.11118 (/app/System.Net.Quic.dll)",
"System.Net.Requests @ 8.0.1425.11118 (/app/System.Net.Requests.dll)",
"System.Net.Security @ 8.0.1425.11118 (/app/System.Net.Security.dll)",
"System.Net.ServicePoint @ 8.0.1425.11118 (/app/System.Net.ServicePoint.dll)",
"System.Net.Sockets @ 8.0.1425.11118 (/app/System.Net.Sockets.dll)",
"System.Net.WebClient @ 8.0.1425.11118 (/app/System.Net.WebClient.dll)",
"System.Net.WebHeaderCollection @ 8.0.1425.11118 (/app/System.Net.WebHeaderCollection.dll)",
"System.Net.WebProxy @ 8.0.1425.11118 (/app/System.Net.WebProxy.dll)",
"System.Net.WebSockets @ 8.0.1425.11118 (/app/System.Net.WebSockets.dll)",
"System.Net.WebSockets.Client @ 8.0.1425.11118 (/app/System.Net.WebSockets.Client.dll)",
"System.Numerics @ 8.0.1425.11118 (/app/System.Numerics.dll)",
"System.Numerics.Vectors @ 8.0.1425.11118 (/app/System.Numerics.Vectors.dll)",
"System.ObjectModel @ 8.0.1425.11118 (/app/System.ObjectModel.dll)",
"System.Private.CoreLib @ 8.0.1425.11118 (/app/System.Private.CoreLib.dll)",
"System.Private.DataContractSerialization @ 8.0.1425.11118 (/app/System.Private.DataContractSerialization.dll)",
"System.Private.Uri @ 8.0.1425.11118 (/app/System.Private.Uri.dll)",
"System.Private.Xml @ 8.0.1425.11118 (/app/System.Private.Xml.dll)",
"System.Private.Xml.Linq @ 8.0.1425.11118 (/app/System.Private.Xml.Linq.dll)",
"System.Reflection @ 8.0.1425.11118 (/app/System.Reflection.dll)",
"System.Reflection.DispatchProxy @ 8.0.1425.11118 (/app/System.Reflection.DispatchProxy.dll)",
"System.Reflection.Emit @ 8.0.1425.11118 (/app/System.Reflection.Emit.dll)",
"System.Reflection.Emit.ILGeneration @ 8.0.1425.11118 (/app/System.Reflection.Emit.ILGeneration.dll)",
"System.Reflection.Emit.Lightweight @ 8.0.1425.11118 (/app/System.Reflection.Emit.Lightweight.dll)",
"System.Reflection.Extensions @ 8.0.1425.11118 (/app/System.Reflection.Extensions.dll)",
"System.Reflection.Metadata @ 8.0.1425.11118 (/app/System.Reflection.Metadata.dll)",
"System.Reflection.Primitives @ 8.0.1425.11118 (/app/System.Reflection.Primitives.dll)",
"System.Reflection.TypeExtensions @ 8.0.1425.11118 (/app/System.Reflection.TypeExtensions.dll)",
"System.Resources.Reader @ 8.0.1425.11118 (/app/System.Resources.Reader.dll)",
"System.Resources.ResourceManager @ 8.0.1425.11118 (/app/System.Resources.ResourceManager.dll)",
"System.Resources.Writer @ 8.0.1425.11118 (/app/System.Resources.Writer.dll)",
"System.Runtime @ 8.0.1425.11118 (/app/System.Runtime.dll)",
"System.Runtime.CompilerServices.Unsafe @ 8.0.1425.11118 (/app/System.Runtime.CompilerServices.Unsafe.dll)",
"System.Runtime.CompilerServices.VisualC @ 8.0.1425.11118 (/app/System.Runtime.CompilerServices.VisualC.dll)",
"System.Runtime.Extensions @ 8.0.1425.11118 (/app/System.Runtime.Extensions.dll)",
"System.Runtime.Handles @ 8.0.1425.11118 (/app/System.Runtime.Handles.dll)",
"System.Runtime.InteropServices @ 8.0.1425.11118 (/app/System.Runtime.InteropServices.dll)",
"System.Runtime.InteropServices.JavaScript @ 8.0.1425.11118 (/app/System.Runtime.InteropServices.JavaScript.dll)",
"System.Runtime.InteropServices.RuntimeInformation @ 8.0.1425.11118 (/app/System.Runtime.InteropServices.RuntimeInformation.dll)",
"System.Runtime.Intrinsics @ 8.0.1425.11118 (/app/System.Runtime.Intrinsics.dll)",
"System.Runtime.Loader @ 8.0.1425.11118 (/app/System.Runtime.Loader.dll)",
"System.Runtime.Numerics @ 8.0.1425.11118 (/app/System.Runtime.Numerics.dll)",
"System.Runtime.Serialization @ 8.0.1425.11118 (/app/System.Runtime.Serialization.dll)",
"System.Runtime.Serialization.Formatters @ 8.0.1425.11118 (/app/System.Runtime.Serialization.Formatters.dll)",
"System.Runtime.Serialization.Json @ 8.0.1425.11118 (/app/System.Runtime.Serialization.Json.dll)",
"System.Runtime.Serialization.Primitives @ 8.0.1425.11118 (/app/System.Runtime.Serialization.Primitives.dll)",
"System.Runtime.Serialization.Xml @ 8.0.1425.11118 (/app/System.Runtime.Serialization.Xml.dll)",
"System.Security @ 8.0.1425.11118 (/app/System.Security.dll)",
"System.Security.AccessControl @ 8.0.1425.11118 (/app/System.Security.AccessControl.dll)",
"System.Security.Claims @ 8.0.1425.11118 (/app/System.Security.Claims.dll)",
"System.Security.Cryptography @ 8.0.1425.11118 (/app/System.Security.Cryptography.dll)",
"System.Security.Cryptography.Algorithms @ 8.0.1425.11118 (/app/System.Security.Cryptography.Algorithms.dll)",
"System.Security.Cryptography.Cng @ 8.0.1425.11118 (/app/System.Security.Cryptography.Cng.dll)",
"System.Security.Cryptography.Csp @ 8.0.1425.11118 (/app/System.Security.Cryptography.Csp.dll)",
"System.Security.Cryptography.Encoding @ 8.0.1425.11118 (/app/System.Security.Cryptography.Encoding.dll)",
"System.Security.Cryptography.OpenSsl @ 8.0.1425.11118 (/app/System.Security.Cryptography.OpenSsl.dll)",
"System.Security.Cryptography.Primitives @ 8.0.1425.11118 (/app/System.Security.Cryptography.Primitives.dll)",
"System.Security.Cryptography.X509Certificates @ 8.0.1425.11118 (/app/System.Security.Cryptography.X509Certificates.dll)",
"System.Security.Principal @ 8.0.1425.11118 (/app/System.Security.Principal.dll)",
"System.Security.Principal.Windows @ 8.0.1425.11118 (/app/System.Security.Principal.Windows.dll)",
"System.Security.SecureString @ 8.0.1425.11118 (/app/System.Security.SecureString.dll)",
"System.ServiceModel.Web @ 8.0.1425.11118 (/app/System.ServiceModel.Web.dll)",
"System.ServiceProcess @ 8.0.1425.11118 (/app/System.ServiceProcess.dll)",
"System.Text.Encoding @ 8.0.1425.11118 (/app/System.Text.Encoding.dll)",
"System.Text.Encoding.CodePages @ 8.0.1425.11118 (/app/System.Text.Encoding.CodePages.dll)",
"System.Text.Encoding.Extensions @ 8.0.1425.11118 (/app/System.Text.Encoding.Extensions.dll)",
"System.Text.Encodings.Web @ 8.0.1425.11118 (/app/System.Text.Encodings.Web.dll)",
"System.Text.Json @ 8.0.1425.11118 (/app/System.Text.Json.dll)",
"System.Text.RegularExpressions @ 8.0.1425.11118 (/app/System.Text.RegularExpressions.dll)",
"System.Threading @ 8.0.1425.11118 (/app/System.Threading.dll)",
"System.Threading.Channels @ 8.0.1425.11118 (/app/System.Threading.Channels.dll)",
"System.Threading.Overlapped @ 8.0.1425.11118 (/app/System.Threading.Overlapped.dll)",
"System.Threading.Tasks @ 8.0.1425.11118 (/app/System.Threading.Tasks.dll)",
"System.Threading.Tasks.Dataflow @ 8.0.1425.11118 (/app/System.Threading.Tasks.Dataflow.dll)",
"System.Threading.Tasks.Extensions @ 8.0.1425.11118 (/app/System.Threading.Tasks.Extensions.dll)",
"System.Threading.Tasks.Parallel @ 8.0.1425.11118 (/app/System.Threading.Tasks.Parallel.dll)",
"System.Threading.Thread @ 8.0.1425.11118 (/app/System.Threading.Thread.dll)",
"System.Threading.ThreadPool @ 8.0.1425.11118 (/app/System.Threading.ThreadPool.dll)",
"System.Threading.Timer @ 8.0.1425.11118 (/app/System.Threading.Timer.dll)",
"System.Transactions @ 8.0.1425.11118 (/app/System.Transactions.dll)",
"System.Transactions.Local @ 8.0.1425.11118 (/app/System.Transactions.Local.dll)",
"System.ValueTuple @ 8.0.1425.11118 (/app/System.ValueTuple.dll)",
"System.Web @ 8.0.1425.11118 (/app/System.Web.dll)",
"System.Web.HttpUtility @ 8.0.1425.11118 (/app/System.Web.HttpUtility.dll)",
"System.Windows @ 8.0.1425.11118 (/app/System.Windows.dll)",
"System.Xml @ 8.0.1425.11118 (/app/System.Xml.dll)",
"System.Xml.Linq @ 8.0.1425.11118 (/app/System.Xml.Linq.dll)",
"System.Xml.ReaderWriter @ 8.0.1425.11118 (/app/System.Xml.ReaderWriter.dll)",
"System.Xml.Serialization @ 8.0.1425.11118 (/app/System.Xml.Serialization.dll)",
"System.Xml.XDocument @ 8.0.1425.11118 (/app/System.Xml.XDocument.dll)",
"System.Xml.XPath @ 8.0.1425.11118 (/app/System.Xml.XPath.dll)",
"System.Xml.XPath.XDocument @ 8.0.1425.11118 (/app/System.Xml.XPath.XDocument.dll)",
"System.Xml.XmlDocument @ 8.0.1425.11118 (/app/System.Xml.XmlDocument.dll)",
"System.Xml.XmlSerializer @ 8.0.1425.11118 (/app/System.Xml.XmlSerializer.dll)",
"WindowsBase @ 8.0.1425.11118 (/app/WindowsBase.dll)",
"mscorlib @ 8.0.1425.11118 (/app/mscorlib.dll)",
"netstandard @ 8.0.1425.11118 (/app/netstandard.dll)",
"Microsoft.Win32.Primitives @ 8.0.14 (/app/Microsoft.Win32.Primitives.dll)",
"Microsoft.Win32.Registry @ 8.0.14 (/app/Microsoft.Win32.Registry.dll)",
"System @ 8.0.14 (/app/System.dll)",
"System.AppContext @ 8.0.14 (/app/System.AppContext.dll)",
"System.Buffers @ 8.0.14 (/app/System.Buffers.dll)",
"System.Collections @ 8.0.14 (/app/System.Collections.dll)",
"System.Collections.Concurrent @ 8.0.14 (/app/System.Collections.Concurrent.dll)",
"System.Collections.Immutable @ 8.0.14 (/app/System.Collections.Immutable.dll)",
"System.Collections.NonGeneric @ 8.0.14 (/app/System.Collections.NonGeneric.dll)",
"System.Collections.Specialized @ 8.0.14 (/app/System.Collections.Specialized.dll)",
"System.ComponentModel @ 8.0.14 (/app/System.ComponentModel.dll)",
"System.ComponentModel.Annotations @ 8.0.14 (/app/System.ComponentModel.Annotations.dll)",
"System.ComponentModel.DataAnnotations @ 8.0.14 (/app/System.ComponentModel.DataAnnotations.dll)",
"System.ComponentModel.EventBasedAsync @ 8.0.14 (/app/System.ComponentModel.EventBasedAsync.dll)",
"System.ComponentModel.Primitives @ 8.0.14 (/app/System.ComponentModel.Primitives.dll)",
"System.ComponentModel.TypeConverter @ 8.0.14 (/app/System.ComponentModel.TypeConverter.dll)",
"System.Configuration @ 8.0.14 (/app/System.Configuration.dll)",
"System.Console @ 8.0.14 (/app/System.Console.dll)",
"System.Core @ 8.0.14 (/app/System.Core.dll)",
"System.Data @ 8.0.14 (/app/System.Data.dll)",
"System.Data.Common @ 8.0.14 (/app/System.Data.Common.dll)",
"System.Data.DataSetExtensions @ 8.0.14 (/app/System.Data.DataSetExtensions.dll)",
"System.Diagnostics.Contracts @ 8.0.14 (/app/System.Diagnostics.Contracts.dll)",
"System.Diagnostics.Debug @ 8.0.14 (/app/System.Diagnostics.Debug.dll)",
"System.Diagnostics.DiagnosticSource @ 8.0.14 (/app/System.Diagnostics.DiagnosticSource.dll)",
"System.Diagnostics.FileVersionInfo @ 8.0.14 (/app/System.Diagnostics.FileVersionInfo.dll)",
"System.Diagnostics.Process @ 8.0.14 (/app/System.Diagnostics.Process.dll)",
"System.Diagnostics.StackTrace @ 8.0.14 (/app/System.Diagnostics.StackTrace.dll)",
"System.Diagnostics.TextWriterTraceListener @ 8.0.14 (/app/System.Diagnostics.TextWriterTraceListener.dll)",
"System.Diagnostics.Tools @ 8.0.14 (/app/System.Diagnostics.Tools.dll)",
"System.Diagnostics.TraceSource @ 8.0.14 (/app/System.Diagnostics.TraceSource.dll)",
"System.Diagnostics.Tracing @ 8.0.14 (/app/System.Diagnostics.Tracing.dll)",
"System.Drawing @ 8.0.14 (/app/System.Drawing.dll)",
"System.Drawing.Primitives @ 8.0.14 (/app/System.Drawing.Primitives.dll)",
"System.Dynamic.Runtime @ 8.0.14 (/app/System.Dynamic.Runtime.dll)",
"System.Formats.Asn1 @ 8.0.14 (/app/System.Formats.Asn1.dll)",
"System.Formats.Tar @ 8.0.14 (/app/System.Formats.Tar.dll)",
"System.Globalization @ 8.0.14 (/app/System.Globalization.dll)",
"System.Globalization.Calendars @ 8.0.14 (/app/System.Globalization.Calendars.dll)",
"System.Globalization.Extensions @ 8.0.14 (/app/System.Globalization.Extensions.dll)",
"System.IO @ 8.0.14 (/app/System.IO.dll)",
"System.IO.Compression @ 8.0.14 (/app/System.IO.Compression.dll)",
"System.IO.Compression.Brotli @ 8.0.14 (/app/System.IO.Compression.Brotli.dll)",
"System.IO.Compression.FileSystem @ 8.0.14 (/app/System.IO.Compression.FileSystem.dll)",
"System.IO.Compression.ZipFile @ 8.0.14 (/app/System.IO.Compression.ZipFile.dll)",
"System.IO.FileSystem @ 8.0.14 (/app/System.IO.FileSystem.dll)",
"System.IO.FileSystem.AccessControl @ 8.0.14 (/app/System.IO.FileSystem.AccessControl.dll)",
"System.IO.FileSystem.DriveInfo @ 8.0.14 (/app/System.IO.FileSystem.DriveInfo.dll)",
"System.IO.FileSystem.Primitives @ 8.0.14 (/app/System.IO.FileSystem.Primitives.dll)",
"System.IO.FileSystem.Watcher @ 8.0.14 (/app/System.IO.FileSystem.Watcher.dll)",
"System.IO.IsolatedStorage @ 8.0.14 (/app/System.IO.IsolatedStorage.dll)",
"System.IO.MemoryMappedFiles @ 8.0.14 (/app/System.IO.MemoryMappedFiles.dll)",
"System.IO.Pipes @ 8.0.14 (/app/System.IO.Pipes.dll)",
"System.IO.Pipes.AccessControl @ 8.0.14 (/app/System.IO.Pipes.AccessControl.dll)",
"System.IO.UnmanagedMemoryStream @ 8.0.14 (/app/System.IO.UnmanagedMemoryStream.dll)",
"System.Linq @ 8.0.14 (/app/System.Linq.dll)",
"System.Linq.Expressions @ 8.0.14 (/app/System.Linq.Expressions.dll)",
"System.Linq.Parallel @ 8.0.14 (/app/System.Linq.Parallel.dll)",
"System.Linq.Queryable @ 8.0.14 (/app/System.Linq.Queryable.dll)",
"System.Memory @ 8.0.14 (/app/System.Memory.dll)",
"System.Net @ 8.0.14 (/app/System.Net.dll)",
"System.Net.Http @ 8.0.14 (/app/System.Net.Http.dll)",
"System.Net.Http.Json @ 8.0.14 (/app/System.Net.Http.Json.dll)",
"System.Net.HttpListener @ 8.0.14 (/app/System.Net.HttpListener.dll)",
"System.Net.Mail @ 8.0.14 (/app/System.Net.Mail.dll)",
"System.Net.NameResolution @ 8.0.14 (/app/System.Net.NameResolution.dll)",
"System.Net.NetworkInformation @ 8.0.14 (/app/System.Net.NetworkInformation.dll)",
"System.Net.Ping @ 8.0.14 (/app/System.Net.Ping.dll)",
"System.Net.Primitives @ 8.0.14 (/app/System.Net.Primitives.dll)",
"System.Net.Quic @ 8.0.14 (/app/System.Net.Quic.dll)",
"System.Net.Requests @ 8.0.14 (/app/System.Net.Requests.dll)",
"System.Net.Security @ 8.0.14 (/app/System.Net.Security.dll)",
"System.Net.ServicePoint @ 8.0.14 (/app/System.Net.ServicePoint.dll)",
"System.Net.Sockets @ 8.0.14 (/app/System.Net.Sockets.dll)",
"System.Net.WebClient @ 8.0.14 (/app/System.Net.WebClient.dll)",
"System.Net.WebHeaderCollection @ 8.0.14 (/app/System.Net.WebHeaderCollection.dll)",
"System.Net.WebProxy @ 8.0.14 (/app/System.Net.WebProxy.dll)",
"System.Net.WebSockets @ 8.0.14 (/app/System.Net.WebSockets.dll)",
"System.Net.WebSockets.Client @ 8.0.14 (/app/System.Net.WebSockets.Client.dll)",
"System.Numerics @ 8.0.14 (/app/System.Numerics.dll)",
"System.Numerics.Vectors @ 8.0.14 (/app/System.Numerics.Vectors.dll)",
"System.ObjectModel @ 8.0.14 (/app/System.ObjectModel.dll)",
"System.Private.CoreLib @ 8.0.14 (/app/System.Private.CoreLib.dll)",
"System.Private.DataContractSerialization @ 8.0.14 (/app/System.Private.DataContractSerialization.dll)",
"System.Private.Uri @ 8.0.14 (/app/System.Private.Uri.dll)",
"System.Private.Xml @ 8.0.14 (/app/System.Private.Xml.dll)",
"System.Private.Xml.Linq @ 8.0.14 (/app/System.Private.Xml.Linq.dll)",
"System.Reflection @ 8.0.14 (/app/System.Reflection.dll)",
"System.Reflection.DispatchProxy @ 8.0.14 (/app/System.Reflection.DispatchProxy.dll)",
"System.Reflection.Emit @ 8.0.14 (/app/System.Reflection.Emit.dll)",
"System.Reflection.Emit.ILGeneration @ 8.0.14 (/app/System.Reflection.Emit.ILGeneration.dll)",
"System.Reflection.Emit.Lightweight @ 8.0.14 (/app/System.Reflection.Emit.Lightweight.dll)",
"System.Reflection.Extensions @ 8.0.14 (/app/System.Reflection.Extensions.dll)",
"System.Reflection.Metadata @ 8.0.14 (/app/System.Reflection.Metadata.dll)",
"System.Reflection.Primitives @ 8.0.14 (/app/System.Reflection.Primitives.dll)",
"System.Reflection.TypeExtensions @ 8.0.14 (/app/System.Reflection.TypeExtensions.dll)",
"System.Resources.Reader @ 8.0.14 (/app/System.Resources.Reader.dll)",
"System.Resources.ResourceManager @ 8.0.14 (/app/System.Resources.ResourceManager.dll)",
"System.Resources.Writer @ 8.0.14 (/app/System.Resources.Writer.dll)",
"System.Runtime @ 8.0.14 (/app/System.Runtime.dll)",
"System.Runtime.CompilerServices.Unsafe @ 8.0.14 (/app/System.Runtime.CompilerServices.Unsafe.dll)",
"System.Runtime.CompilerServices.VisualC @ 8.0.14 (/app/System.Runtime.CompilerServices.VisualC.dll)",
"System.Runtime.Extensions @ 8.0.14 (/app/System.Runtime.Extensions.dll)",
"System.Runtime.Handles @ 8.0.14 (/app/System.Runtime.Handles.dll)",
"System.Runtime.InteropServices @ 8.0.14 (/app/System.Runtime.InteropServices.dll)",
"System.Runtime.InteropServices.JavaScript @ 8.0.14 (/app/System.Runtime.InteropServices.JavaScript.dll)",
"System.Runtime.InteropServices.RuntimeInformation @ 8.0.14 (/app/System.Runtime.InteropServices.RuntimeInformation.dll)",
"System.Runtime.Intrinsics @ 8.0.14 (/app/System.Runtime.Intrinsics.dll)",
"System.Runtime.Loader @ 8.0.14 (/app/System.Runtime.Loader.dll)",
"System.Runtime.Numerics @ 8.0.14 (/app/System.Runtime.Numerics.dll)",
"System.Runtime.Serialization @ 8.0.14 (/app/System.Runtime.Serialization.dll)",
"System.Runtime.Serialization.Formatters @ 8.0.14 (/app/System.Runtime.Serialization.Formatters.dll)",
"System.Runtime.Serialization.Json @ 8.0.14 (/app/System.Runtime.Serialization.Json.dll)",
"System.Runtime.Serialization.Primitives @ 8.0.14 (/app/System.Runtime.Serialization.Primitives.dll)",
"System.Runtime.Serialization.Xml @ 8.0.14 (/app/System.Runtime.Serialization.Xml.dll)",
"System.Security @ 8.0.14 (/app/System.Security.dll)",
"System.Security.AccessControl @ 8.0.14 (/app/System.Security.AccessControl.dll)",
"System.Security.Claims @ 8.0.14 (/app/System.Security.Claims.dll)",
"System.Security.Cryptography @ 8.0.14 (/app/System.Security.Cryptography.dll)",
"System.Security.Cryptography.Algorithms @ 8.0.14 (/app/System.Security.Cryptography.Algorithms.dll)",
"System.Security.Cryptography.Cng @ 8.0.14 (/app/System.Security.Cryptography.Cng.dll)",
"System.Security.Cryptography.Csp @ 8.0.14 (/app/System.Security.Cryptography.Csp.dll)",
"System.Security.Cryptography.Encoding @ 8.0.14 (/app/System.Security.Cryptography.Encoding.dll)",
"System.Security.Cryptography.OpenSsl @ 8.0.14 (/app/System.Security.Cryptography.OpenSsl.dll)",
"System.Security.Cryptography.Primitives @ 8.0.14 (/app/System.Security.Cryptography.Primitives.dll)",
"System.Security.Cryptography.X509Certificates @ 8.0.14 (/app/System.Security.Cryptography.X509Certificates.dll)",
"System.Security.Principal @ 8.0.14 (/app/System.Security.Principal.dll)",
"System.Security.Principal.Windows @ 8.0.14 (/app/System.Security.Principal.Windows.dll)",
"System.Security.SecureString @ 8.0.14 (/app/System.Security.SecureString.dll)",
"System.ServiceModel.Web @ 8.0.14 (/app/System.ServiceModel.Web.dll)",
"System.ServiceProcess @ 8.0.14 (/app/System.ServiceProcess.dll)",
"System.Text.Encoding @ 8.0.14 (/app/System.Text.Encoding.dll)",
"System.Text.Encoding.CodePages @ 8.0.14 (/app/System.Text.Encoding.CodePages.dll)",
"System.Text.Encoding.Extensions @ 8.0.14 (/app/System.Text.Encoding.Extensions.dll)",
"System.Text.Encodings.Web @ 8.0.14 (/app/System.Text.Encodings.Web.dll)",
"System.Text.Json @ 8.0.14 (/app/System.Text.Json.dll)",
"System.Text.RegularExpressions @ 8.0.14 (/app/System.Text.RegularExpressions.dll)",
"System.Threading @ 8.0.14 (/app/System.Threading.dll)",
"System.Threading.Channels @ 8.0.14 (/app/System.Threading.Channels.dll)",
"System.Threading.Overlapped @ 8.0.14 (/app/System.Threading.Overlapped.dll)",
"System.Threading.Tasks @ 8.0.14 (/app/System.Threading.Tasks.dll)",
"System.Threading.Tasks.Dataflow @ 8.0.14 (/app/System.Threading.Tasks.Dataflow.dll)",
"System.Threading.Tasks.Extensions @ 8.0.14 (/app/System.Threading.Tasks.Extensions.dll)",
"System.Threading.Tasks.Parallel @ 8.0.14 (/app/System.Threading.Tasks.Parallel.dll)",
"System.Threading.Thread @ 8.0.14 (/app/System.Threading.Thread.dll)",
"System.Threading.ThreadPool @ 8.0.14 (/app/System.Threading.ThreadPool.dll)",
"System.Threading.Timer @ 8.0.14 (/app/System.Threading.Timer.dll)",
"System.Transactions @ 8.0.14 (/app/System.Transactions.dll)",
"System.Transactions.Local @ 8.0.14 (/app/System.Transactions.Local.dll)",
"System.ValueTuple @ 8.0.14 (/app/System.ValueTuple.dll)",
"System.Web @ 8.0.14 (/app/System.Web.dll)",
"System.Web.HttpUtility @ 8.0.14 (/app/System.Web.HttpUtility.dll)",
"System.Windows @ 8.0.14 (/app/System.Windows.dll)",
"System.Xml @ 8.0.14 (/app/System.Xml.dll)",
"System.Xml.Linq @ 8.0.14 (/app/System.Xml.Linq.dll)",
"System.Xml.ReaderWriter @ 8.0.14 (/app/System.Xml.ReaderWriter.dll)",
"System.Xml.Serialization @ 8.0.14 (/app/System.Xml.Serialization.dll)",
"System.Xml.XDocument @ 8.0.14 (/app/System.Xml.XDocument.dll)",
"System.Xml.XPath @ 8.0.14 (/app/System.Xml.XPath.dll)",
"System.Xml.XPath.XDocument @ 8.0.14 (/app/System.Xml.XPath.XDocument.dll)",
"System.Xml.XmlDocument @ 8.0.14 (/app/System.Xml.XmlDocument.dll)",
"System.Xml.XmlSerializer @ 8.0.14 (/app/System.Xml.XmlSerializer.dll)",
"WindowsBase @ 8.0.14 (/app/WindowsBase.dll)",
"mscorlib @ 8.0.14 (/app/mscorlib.dll)",
"netstandard @ 8.0.14 (/app/netstandard.dll)",
)
assertAllDepEntriesInEmbeddedExecutable := func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
@@ -730,7 +730,10 @@ func TestCataloger(t *testing.T) {
if len(p.CPEs) == 0 {
continue
}
assert.Contains(t, p.Name, "Microsoft.NETCore.App")
if runtimeFamilyFromName(p.Name) != netRuntimeFamily {
continue
}
assert.Equal(t, runtimeCPEs(p.Name, p.Version), p.CPEs)
return
}
t.Error("expected at least one runtime package with a CPE")
@@ -1186,6 +1189,7 @@ func TestCataloger(t *testing.T) {
"runtime.linux-x64.Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)", // a compile target reference
},
expectedRels: []string{
"Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] helloworld @ 1.0.0 (/app/helloworld.deps.json)",
"Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
"Serilog @ 2.10.0 (/app/helloworld.deps.json) [dependency-of] Serilog.Sinks.Console @ 4.0.1 (/app/helloworld.deps.json)",
"Serilog @ 2.10.0 (/app/helloworld.deps.json) [dependency-of] helloworld @ 1.0.0 (/app/helloworld.deps.json)",
@@ -108,7 +108,7 @@ func (c depsBinaryCataloger) Catalog(_ context.Context, resolver file.Resolver)
Name: "Microsoft.NETCore.App",
Version: version,
Type: pkg.DotnetPkg,
CPEs: runtimeCPEs(version),
CPEs: runtimeCPEs("Microsoft.NETCore.App", version),
Locations: file.NewLocationSet(locs...),
}
pkgs = append(pkgs, rtp)
+97 -39
View File
@@ -22,6 +22,14 @@ var (
versionPunctuationRegex = regexp.MustCompile(`[.,]+`)
)
type runtimeFamily string
const (
unknownRuntimeFamily runtimeFamily = ""
netRuntimeFamily runtimeFamily = "net"
aspNetCoreRuntimeFamily runtimeFamily = "aspnet_core"
)
// newDotnetDepsPackage creates a new Dotnet dependency package from a logicalDepsJSONPackage.
// Note that the new logicalDepsJSONPackage now directly holds library and executable information.
func newDotnetDepsPackage(lp logicalDepsJSONPackage, depsLocation file.Location) *pkg.Package {
@@ -36,7 +44,7 @@ func newDotnetDepsPackage(lp logicalDepsJSONPackage, depsLocation file.Location)
var cpes []cpe.CPE
if isRuntime(name) {
cpes = runtimeCPEs(ver)
cpes = runtimeCPEs(name, ver)
}
p := &pkg.Package{
@@ -56,52 +64,68 @@ func newDotnetDepsPackage(lp logicalDepsJSONPackage, depsLocation file.Location)
}
func isRuntime(name string) bool {
// found in a self-contained net8 app in the deps.json for the application
selfContainedRuntimeDependency := strings.HasPrefix(name, "runtimepack.Microsoft.NETCore.App.Runtime")
// found in net8 apps in the deps.json for the runtime
explicitRuntimeDependency := strings.HasPrefix(name, "Microsoft.NETCore.App.Runtime")
// found in net2 apps in the deps.json for the runtime
producesARuntime := strings.HasPrefix(name, "runtime") && strings.HasSuffix(name, "Microsoft.NETCore.App")
return selfContainedRuntimeDependency || explicitRuntimeDependency || producesARuntime
return runtimeFamilyFromName(name) != unknownRuntimeFamily
}
func runtimeCPEs(ver string) []cpe.CPE {
// .NET Core Versions
// 2016: .NET Core 1.0, cpe:2.3:a:microsoft:dotnet_core:1.0:*:*:*:*:*:*:*
// 2016: .NET Core 1.1, cpe:2.3:a:microsoft:dotnet_core:1.1:*:*:*:*:*:*:*
// 2017: .NET Core 2.0, cpe:2.3:a:microsoft:dotnet_core:2.0:*:*:*:*:*:*:*
// 2018: .NET Core 2.1, cpe:2.3:a:microsoft:dotnet_core:2.1:*:*:*:*:*:*:*
// 2018: .NET Core 2.2, cpe:2.3:a:microsoft:dotnet_core:2.2:*:*:*:*:*:*:*
// 2019: .NET Core 3.0, cpe:2.3:a:microsoft:dotnet_core:3.0:*:*:*:*:*:*:*
// 2019: .NET Core 3.1, cpe:2.3:a:microsoft:dotnet_core:3.1:*:*:*:*:*:*:*
func runtimeFamilyFromName(name string) runtimeFamily {
normalizedName := strings.ToLower(name)
// Unified .NET Versions
// 2020: .NET 5.0, cpe:2.3:a:microsoft:dotnet:5.0:*:*:*:*:*:*:*
// 2021: .NET 6.0, cpe:2.3:a:microsoft:dotnet:6.0:*:*:*:*:*:*:*
// 2022: .NET 7.0, cpe:2.3:a:microsoft:dotnet:7.0:*:*:*:*:*:*:*
// 2023: .NET 8.0, cpe:2.3:a:microsoft:dotnet:8.0:*:*:*:*:*:*:*
// 2024: .NET 9.0, cpe:2.3:a:microsoft:dotnet:9.0:*:*:*:*:*:*:*
// 2025 ...?
// found in self-contained or framework-dependent apps in deps.json entries
if strings.HasPrefix(normalizedName, "runtimepack.microsoft.aspnetcore.app.runtime") ||
strings.HasPrefix(normalizedName, "microsoft.aspnetcore.app.runtime") ||
normalizedName == "microsoft.aspnetcore.app" ||
(strings.HasPrefix(normalizedName, "runtime") && strings.HasSuffix(normalizedName, "microsoft.aspnetcore.app")) {
return aspNetCoreRuntimeFamily
}
fields := strings.Split(ver, ".")
majorVersion, err := strconv.Atoi(fields[0])
if err != nil {
log.WithFields("error", err).Tracef("failed to parse .NET major version from %q", ver)
// found in self-contained, framework-dependent, and synthesized runtime packages
if strings.HasPrefix(normalizedName, "runtimepack.microsoft.netcore.app.runtime") ||
strings.HasPrefix(normalizedName, "microsoft.netcore.app.runtime") ||
normalizedName == "microsoft.netcore.app" ||
(strings.HasPrefix(normalizedName, "runtime") && strings.HasSuffix(normalizedName, "microsoft.netcore.app")) {
return netRuntimeFamily
}
return unknownRuntimeFamily
}
func runtimeCPEs(name, ver string) []cpe.CPE {
family := runtimeFamilyFromName(name)
if family == unknownRuntimeFamily {
return nil
}
var minorVersion int
if len(fields) > 1 {
minorVersion, err = strconv.Atoi(fields[1])
if err != nil {
log.WithFields("error", err).Tracef("failed to parse .NET minor version from %q", ver)
return nil
}
fields := strings.Split(ver, ".")
if len(fields) == 0 {
return nil
}
productName := "dotnet"
if majorVersion < 5 {
productName = "dotnet_core"
normalizedVersionFields := make([]string, 0, len(fields))
majorVersion, err := strconv.Atoi(fields[0])
if err != nil {
log.WithFields("error", err).Tracef("failed to parse .NET runtime major version from %q", ver)
return nil
}
normalizedVersionFields = append(normalizedVersionFields, strconv.Itoa(majorVersion))
for _, field := range fields[1:] {
value, err := strconv.Atoi(field)
if err != nil {
log.WithFields("error", err).Tracef("failed to parse .NET runtime version component %q from %q", field, ver)
return nil
}
normalizedVersionFields = append(normalizedVersionFields, strconv.Itoa(value))
}
if len(normalizedVersionFields) == 1 {
normalizedVersionFields = append(normalizedVersionFields, "0")
}
productName := ".net"
if family == aspNetCoreRuntimeFamily {
productName = "asp.net_core"
} else if majorVersion < 5 {
productName = ".net_core"
}
return []cpe.CPE{
@@ -110,7 +134,7 @@ func runtimeCPEs(ver string) []cpe.CPE {
Part: "a",
Vendor: "microsoft",
Product: productName,
Version: fmt.Sprintf("%d.%d", majorVersion, minorVersion),
Version: strings.Join(normalizedVersionFields, "."),
},
// we didn't find this in the underlying material, but this is the convention in NVD and we are certain this is a runtime package
Source: cpe.DeclaredSource,
@@ -323,6 +347,13 @@ func findVersionFromVersionResources(versionResources map[string]string) string
productVersion := extractVersionFromResourcesValue(versionResources["ProductVersion"])
fileVersion := extractVersionFromResourcesValue(versionResources["FileVersion"])
// ms file ver is a ci build stamp (major.minor.<buildfate>.<buildyime>) we'll match with fewer segments
if isMicrosoftVersionResource(versionResources) {
if v := preferShorterMajorMinorMatch(productVersion, fileVersion); v != "" {
return v
}
}
semanticVersionCompareResult := keepGreaterSemanticVersion(productVersion, fileVersion)
if semanticVersionCompareResult != "" {
return semanticVersionCompareResult
@@ -363,6 +394,33 @@ func extractVersionFromResourcesValue(version string) string {
return out
}
// preferShorterMajorMinorMatch returns productVersion when it shares major.minor
// with fileversion and has fewer segments "" otherwise
func preferShorterMajorMinorMatch(productVersion, fileVersion string) string {
semanticProductVersion, err := version.NewVersion(productVersion)
if err != nil || semanticProductVersion == nil {
return ""
}
semanticFileVersion, err := version.NewVersion(fileVersion)
if err != nil || semanticFileVersion == nil {
return ""
}
productSegments := semanticProductVersion.Segments()
fileSegments := semanticFileVersion.Segments()
if len(productSegments) < 2 || len(fileSegments) < 2 {
return ""
}
if productSegments[0] != fileSegments[0] || productSegments[1] != fileSegments[1] {
return ""
}
if len(productSegments) >= len(fileSegments) {
return ""
}
// 1.0.7+sha -> 1.0.7
v, _, _ := strings.Cut(productVersion, "+")
return v
}
func keepGreaterSemanticVersion(productVersion string, fileVersion string) string {
semanticProductVersion, err := version.NewVersion(productVersion)
if err != nil || semanticProductVersion == nil {
+151 -54
View File
@@ -46,6 +46,56 @@ func Test_getDepsJSONFilePrefix(t *testing.T) {
}
}
func Test_newDotnetDepsPackage_AssignsRuntimeCPEs(t *testing.T) {
tests := []struct {
name string
nameVersion string
expected []cpe.CPE
}{
{
name: ".NET runtime package",
nameVersion: "runtimepack.Microsoft.NETCore.App.Runtime.win-x64/10.0.4",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: ".net",
Version: "10.0.4",
},
Source: cpe.DeclaredSource,
},
},
},
{
name: "ASP.NET Core runtime package",
nameVersion: "runtimepack.Microsoft.AspNetCore.App.Runtime.win-x64/10.0.4",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "asp.net_core",
Version: "10.0.4",
},
Source: cpe.DeclaredSource,
},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
actual := newDotnetDepsPackage(
logicalDepsJSONPackage{NameVersion: tc.nameVersion},
file.NewLocation("/app/test.deps.json"),
)
assert.Equal(t, tc.expected, actual.CPEs)
})
}
}
func Test_NewDotnetBinaryPackage(t *testing.T) {
tests := []struct {
name string
@@ -302,6 +352,24 @@ func Test_NewDotnetBinaryPackage(t *testing.T) {
Version: "3.0.0.0",
},
},
{
name: "Microsoft assembly with CI-stamped FileVersion prefers ProductVersion",
versionResources: map[string]string{
"CompanyName": "Microsoft Corporation",
"ProductName": "Microsoft ASP.NET Core",
"FileVersion": "10.0.726.21808",
"ProductVersion": "10.0.7+b16286c2284fecf303dbc12a0bb152476d662e44",
},
expectedPackage: pkg.Package{
Name: "Microsoft ASP.NET Core",
Version: "10.0.7",
Metadata: pkg.DotnetPortableExecutableEntry{
CompanyName: "Microsoft Corporation",
ProductName: "Microsoft ASP.NET Core",
ProductVersion: "10.0.7+b16286c2284fecf303dbc12a0bb152476d662e44",
},
},
},
}
for _, tc := range tests {
@@ -382,19 +450,21 @@ func Test_spaceNormalize(t *testing.T) {
func TestRuntimeCPEs(t *testing.T) {
tests := []struct {
name string
version string
expected []cpe.CPE
name string
packageName string
version string
expected []cpe.CPE
}{
{
name: ".NET Core 1.0",
version: "1.0",
name: ".NET Core 1.0",
packageName: "Microsoft.NETCore.App",
version: "1.0",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet_core",
Product: ".net_core",
Version: "1.0",
},
Source: cpe.DeclaredSource,
@@ -402,14 +472,15 @@ func TestRuntimeCPEs(t *testing.T) {
},
},
{
name: ".NET Core 2.1",
version: "2.1",
name: ".NET Core 2.1",
packageName: "Microsoft.NETCore.App",
version: "2.1",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet_core",
Product: ".net_core",
Version: "2.1",
},
Source: cpe.DeclaredSource,
@@ -417,14 +488,15 @@ func TestRuntimeCPEs(t *testing.T) {
},
},
{
name: ".NET Core 3.1",
version: "3.1",
name: ".NET Core 3.1",
packageName: "Microsoft.NETCore.App",
version: "3.1",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet_core",
Product: ".net_core",
Version: "3.1",
},
Source: cpe.DeclaredSource,
@@ -432,14 +504,15 @@ func TestRuntimeCPEs(t *testing.T) {
},
},
{
name: ".NET Core 4.9 (hypothetical)",
version: "4.9",
name: ".NET Core 4.9 (hypothetical)",
packageName: "Microsoft.NETCore.App",
version: "4.9",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet_core",
Product: ".net_core",
Version: "4.9",
},
Source: cpe.DeclaredSource,
@@ -447,14 +520,15 @@ func TestRuntimeCPEs(t *testing.T) {
},
},
{
name: ".NET 5.0",
version: "5.0",
name: ".NET 5.0",
packageName: "Microsoft.NETCore.App",
version: "5.0",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet",
Product: ".net",
Version: "5.0",
},
Source: cpe.DeclaredSource,
@@ -462,14 +536,15 @@ func TestRuntimeCPEs(t *testing.T) {
},
},
{
name: ".NET 6.0",
version: "6.0",
name: ".NET 6.0",
packageName: "Microsoft.NETCore.App",
version: "6.0",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet",
Product: ".net",
Version: "6.0",
},
Source: cpe.DeclaredSource,
@@ -477,14 +552,15 @@ func TestRuntimeCPEs(t *testing.T) {
},
},
{
name: ".NET 8.0",
version: "8.0",
name: ".NET 8.0",
packageName: "Microsoft.NETCore.App",
version: "8.0",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet",
Product: ".net",
Version: "8.0",
},
Source: cpe.DeclaredSource,
@@ -492,14 +568,15 @@ func TestRuntimeCPEs(t *testing.T) {
},
},
{
name: ".NET 10.0 (future version)",
version: "10.0",
name: ".NET 10.0 (future version)",
packageName: "Microsoft.NETCore.App",
version: "10.0",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet",
Product: ".net",
Version: "10.0",
},
Source: cpe.DeclaredSource,
@@ -507,14 +584,47 @@ func TestRuntimeCPEs(t *testing.T) {
},
},
{
name: "Patch version should not be included",
version: "6.0.21",
name: "Patch version should be preserved",
packageName: "Microsoft.NETCore.App",
version: "6.0.21",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet",
Product: ".net",
Version: "6.0.21",
},
Source: cpe.DeclaredSource,
},
},
},
{
name: "ASP.NET Core runtime",
packageName: "runtimepack.Microsoft.AspNetCore.App.Runtime.win-x64",
version: "9.0.10",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "asp.net_core",
Version: "9.0.10",
},
Source: cpe.DeclaredSource,
},
},
},
{
name: "Assumed minor version",
packageName: "Microsoft.NETCore.App",
version: "6",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: ".net",
Version: "6.0",
},
Source: cpe.DeclaredSource,
@@ -522,39 +632,26 @@ func TestRuntimeCPEs(t *testing.T) {
},
},
{
name: "Assumed minor version",
version: "6",
expected: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "microsoft",
Product: "dotnet",
Version: "6.0",
},
Source: cpe.DeclaredSource,
},
},
name: "Invalid version format",
packageName: "Microsoft.NETCore.App",
version: "invalid",
expected: nil,
},
{
name: "Invalid version format",
version: "invalid",
expected: nil,
},
{
name: "Empty version",
version: "",
expected: nil,
name: "Empty version",
packageName: "Microsoft.NETCore.App",
version: "",
expected: nil,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result := runtimeCPEs(tc.version)
result := runtimeCPEs(tc.packageName, tc.version)
if !reflect.DeepEqual(result, tc.expected) {
t.Errorf("runtimeCPEs(%q) = %+v; want %+v",
tc.version, result, tc.expected)
t.Errorf("runtimeCPEs(%q, %q) = %+v; want %+v",
tc.packageName, tc.version, result, tc.expected)
}
})
}
@@ -120,6 +120,20 @@ func MatchAll(matchers ...EvidenceMatcher) EvidenceMatcher {
}
}
// MatchNone succeeds only if the matcher returns no results.
func MatchNone(matcher EvidenceMatcher) EvidenceMatcher {
return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) {
match, err := matcher(classifier, context)
if err != nil {
return nil, err
}
if match != nil {
return nil, nil
}
return []pkg.Package{}, nil
}
}
type ContextualEvidenceMatchers struct {
CatalogerName string
}
@@ -243,3 +243,40 @@ func Test_SupportingEvidenceMatcher(t *testing.T) {
})
}
}
func TestMatchNone(t *testing.T) {
matchingMatcher := MatchPath("**")
notMatchingMatcher := MatchPath("will-not-match")
tests := []struct {
name string
matcher EvidenceMatcher
expected bool // true if MatchNone should succeed (inner failed)
}{
{
name: "inner matches, MatchNone fails",
matcher: MatchNone(matchingMatcher),
expected: false,
},
{
name: "inner fails, MatchNone succeeds",
matcher: MatchNone(notMatchingMatcher),
expected: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pkgs, err := tt.matcher(Classifier{}, MatcherContext{
Location: file.NewLocation("some/path"),
})
require.NoError(t, err)
if tt.expected {
assert.NotNil(t, pkgs)
assert.Empty(t, pkgs)
} else {
assert.Nil(t, pkgs)
}
})
}
}
@@ -76,6 +76,9 @@
"github.com/go-git/go-git": [
"cpe:2.3:a:go-git_project:go-git:*:*:*:*:*:go:*:*"
],
"github.com/go-jose/go-jose/v4#pkg-constants": [
"cpe:2.3:a:go-jose_project:go-jose:*:*:*:*:*:*:*:*"
],
"github.com/go-resty/resty/v2": [
"cpe:2.3:a:resty_project:resty:*:*:*:*:*:go:*:*"
],
@@ -151,6 +154,9 @@
"github.com/rezmoss/axios4go": [
"cpe:2.3:a:rezmoss:axios4go:*:*:*:*:*:go:*:*"
],
"github.com/russellhaering/goxmldsig": [
"cpe:2.3:a:goxmldsig_project:goxmldsig:*:*:*:*:*:*:*:*"
],
"github.com/sap/cloud-security-client-go": [
"cpe:2.3:a:sap:cloud-security-client-go:*:*:*:*:*:go:*:*"
],
@@ -160,6 +166,9 @@
"github.com/sigstore/gitsign": [
"cpe:2.3:a:sigstore:gitsign:*:*:*:*:*:go:*:*"
],
"github.com/sipeed/picoclaw": [
"cpe:2.3:a:sipeed:picoclaw:*:*:*:*:*:go:*:*"
],
"github.com/sirupsen/logrus": [
"cpe:2.3:a:turbopuffer:logrus:*:*:*:*:*:go:*:*"
],
@@ -169,12 +178,27 @@
"github.com/stacklok/minder": [
"cpe:2.3:a:lfprojects:minder:*:*:*:*:*:go:*:*"
],
"github.com/tomwright/dasel": [
"cpe:2.3:a:tomwright:dasel:*:*:*:*:*:go:*:*"
],
"github.com/tomwright/dasel/v2": [
"cpe:2.3:a:tomwright:dasel:*:*:*:*:*:go:*:*"
],
"github.com/tomwright/dasel/v3": [
"cpe:2.3:a:tomwright:dasel:*:*:*:*:*:go:*:*"
],
"github.com/valyala/fasthttp": [
"cpe:2.3:a:fasthttp_project:fasthttp:*:*:*:*:*:*:*:*"
],
"github.com/whilp/git-urls": [
"cpe:2.3:a:git-urls_project:git-urls:*:*:*:*:*:go:*:*"
],
"github.com/yuin/goldmark": [
"cpe:2.3:a:yuin:goldmark:*:*:*:*:*:go:*:*"
],
"go.opentelemetry.io/otel": [
"cpe:2.3:a:opentelemetry:opentelemetry:*:*:*:*:*:go:*:*"
],
"golang.org/x/crypto": [
"cpe:2.3:a:go:ssh:*:*:*:*:*:go:*:*"
],
@@ -2222,6 +2246,9 @@
"626": [
"cpe:2.3:a:626_project:626:*:*:*:*:*:node.js:*:*"
],
"@aborruso/ckan-mcp-server": [
"cpe:2.3:a:ondata:ckan_mcp_server:*:*:*:*:*:node.js:*:*"
],
"@actions/artifact": [
"cpe:2.3:a:github:actions\\/artifact:*:*:*:*:*:node.js:*:*"
],
@@ -2248,6 +2275,9 @@
"@anthropic-ai/claude-code": [
"cpe:2.3:a:anthropic:claude_code:*:*:*:*:*:node.js:*:*"
],
"@anthropic-ai/sdk": [
"cpe:2.3:a:anthropic:claude_sdk_for_typescript:*:*:*:*:*:*:*:*"
],
"@apollo/gateway": [
"cpe:2.3:a:apollographql:apollo_gateway:*:*:*:*:*:node.js:*:*"
],
@@ -2257,6 +2287,9 @@
"@apollosproject/data-connector-rock": [
"cpe:2.3:a:apollosapp:data-connector-rock:*:*:*:*:*:node.js:*:*"
],
"@appium/support": [
"cpe:2.3:a:appium:appium\\/support:*:*:*:*:*:node.js:*:*"
],
"@astrojs/cloudflare": [
"cpe:2.3:a:astro:\\@astrojs\\/cloudflare:*:*:*:*:*:node.js:*:*"
],
@@ -2284,12 +2317,21 @@
"@backstage/backend-common": [
"cpe:2.3:a:linuxfoundation:backstage_backend-common:*:*:*:*:*:node.js:*:*"
],
"@backstage/integration": [
"cpe:2.3:a:linuxfoundation:backstage\\/integration:*:*:*:*:*:node.js:*:*"
],
"@backstage/plugin-auth-backend": [
"cpe:2.3:a:linuxfoundation:auth_backend:*:*:*:*:*:node.js:*:*"
],
"@backstage/plugin-scaffolder-backend": [
"cpe:2.3:a:linuxfoundation:backstage\\/plugin-scaffolder-backend:*:*:*:*:*:*:*:*"
],
"@backstage/plugin-techdocs": [
"cpe:2.3:a:linuxfoundation:\\@backstage\\/plugin-techdocs:*:*:*:*:*:node.js:*:*"
],
"@backstage/plugin-techdocs-node": [
"cpe:2.3:a:linuxfoundation:backstage_plugin-techdocs-node:*:*:*:*:*:*:*:*"
],
"@backstage/techdocs-common": [
"cpe:2.3:a:linuxfoundation:\\@backstage\\/techdocs-common:*:*:*:*:*:node.js:*:*"
],
@@ -2350,6 +2392,9 @@
"@evershop/evershop": [
"cpe:2.3:a:evershop:evershop:*:*:*:*:*:node.js:*:*"
],
"@fastify/middie": [
"cpe:2.3:a:openjsf:\\@fastify\\/middie:*:*:*:*:*:fastify:*:*"
],
"@fastly/js-compute": [
"cpe:2.3:a:fastly:js-compute:*:*:*:*:*:node.js:*:*"
],
@@ -2365,6 +2410,12 @@
"@flourish/sdk": [
"cpe:2.3:a:canva:flourish_sdk:*:*:*:*:*:node.js:*:*"
],
"@frontmcp/adapters": [
"cpe:2.3:a:agentfront:\\@frontmcp\\/adapters:*:*:*:*:*:node.js:*:*"
],
"@frontmcp/sdk": [
"cpe:2.3:a:agentfront:\\@frontmcp\\/sdk:*:*:*:*:*:node.js:*:*"
],
"@github/paste-markdown": [
"cpe:2.3:a:paste-markdown_project:paste-markdown:*:*:*:*:*:node.js:*:*"
],
@@ -2389,6 +2440,9 @@
"@joeattardi/emoji-button": [
"cpe:2.3:a:emoji_button_project:emoji_button:*:*:*:*:*:node.js:*:*"
],
"@keystone-6/core": [
"cpe:2.3:a:keystonejs:keystone:*:*:*:*:*:node.js:*:*"
],
"@keystonejs/keystone": [
"cpe:2.3:a:keystonejs:keystone:*:*:*:*:*:node.js:*:*"
],
@@ -2407,6 +2461,9 @@
"@misskey-dev/summaly": [
"cpe:2.3:a:misskey:summaly:*:*:*:*:*:node.js:*:*"
],
"@mobilenext/mobile-mcp": [
"cpe:2.3:a:mobilenexthq:mobile_mcp:*:*:*:*:*:node.js:*:*"
],
"@nestjs/core": [
"cpe:2.3:a:nestjs:nest:*:*:*:*:*:node.js:*:*"
],
@@ -2431,6 +2488,12 @@
"@octokit/webhooks": [
"cpe:2.3:a:octokit:webhooks:*:*:*:*:*:node.js:*:*"
],
"@openclaw/voice-call": [
"cpe:2.3:a:openclaw:openclaw\\/voice-call:*:*:*:*:*:node.js:*:*"
],
"@opennextjs/cloudflare": [
"cpe:2.3:a:opennextjs:opennext_for_cloudflare:*:*:*:*:*:node.js:*:*"
],
"@openzeppelin/contracts": [
"cpe:2.3:a:openzeppelin:contracts:*:*:*:*:*:node.js:*:*"
],
@@ -2456,6 +2519,9 @@
"@rkesters/gnuplot": [
"cpe:2.3:a:gnuplot_project:gnuplot:*:*:*:*:*:node.js:*:*"
],
"@saltcorn/server": [
"cpe:2.3:a:saltcorn:saltcorn:*:*:*:*:*:*:*:*"
],
"@sap/xssec": [
"cpe:2.3:a:sap:\\@sap\\/xssec:*:*:*:*:*:node.js:*:*"
],
@@ -2749,6 +2815,9 @@
"box2d-native": [
"cpe:2.3:a:box2d-native_project:box2d-native:*:*:*:*:*:node.js:*:*"
],
"brace-expansion": [
"cpe:2.3:a:juliangruber:brace-expansion:*:*:*:*:*:node.js:*:*"
],
"braces": [
"cpe:2.3:a:braces_project:braces:*:*:*:*:*:node.js:*:*",
"cpe:2.3:a:jonschlinkert:braces:*:*:*:*:*:node.js:*:*"
@@ -2859,6 +2928,9 @@
"class-transformer": [
"cpe:2.3:a:class-transformer_project:class-transformer:*:*:*:*:*:node.js:*:*"
],
"clawdbot": [
"cpe:2.3:a:openclaw:openclaw:*:*:*:*:*:node.js:*:*"
],
"cli": [
"cpe:2.3:a:cli_project:cli:*:*:*:*:*:node.js:*:*"
],
@@ -3100,6 +3172,9 @@
"defaults-deep": [
"cpe:2.3:a:defaults-deep_project:defaults-deep:*:*:*:*:*:node.js:*:*"
],
"defu": [
"cpe:2.3:a:unjs:defu:*:*:*:*:*:node.js:*:*"
],
"defuddle": [
"cpe:2.3:a:kepano:defuddle:*:*:*:*:*:node.js:*:*"
],
@@ -3182,6 +3257,9 @@
"dotty": [
"cpe:2.3:a:dotty_project:dotty:*:*:*:*:*:*:*:*"
],
"drizzle-orm": [
"cpe:2.3:a:drizzle:drizzle:*:*:*:*:*:node.js:*:*"
],
"droppy": [
"cpe:2.3:a:droppy_project:droppy:*:*:*:*:*:node.js:*:*"
],
@@ -3216,7 +3294,8 @@
"cpe:2.3:a:adonisjs:edge:*:*:*:*:*:node.js:*:*"
],
"effect": [
"cpe:2.3:a:effect_project:effect:*:*:*:*:*:node.js:*:*"
"cpe:2.3:a:effect_project:effect:*:*:*:*:*:node.js:*:*",
"cpe:2.3:a:effectful:effect:*:*:*:*:*:node.js:*:*"
],
"egg-scripts": [
"cpe:2.3:a:eggjs:egg-scripts:*:*:*:*:*:node.js:*:*"
@@ -4069,6 +4148,9 @@
"launchpad": [
"cpe:2.3:a:bitovi:launchpad:*:*:*:*:*:node.js:*:*"
],
"leaflet": [
"cpe:2.3:a:leafletjs:leaflet:*:*:*:*:*:node.js:*:*"
],
"less-openui5": [
"cpe:2.3:a:less-openui5_project:less-openui5:*:*:*:*:*:node.js:*:*"
],
@@ -4147,6 +4229,18 @@
"lodash": [
"cpe:2.3:a:lodash:lodash:*:*:*:*:*:node.js:*:*"
],
"lodash-amd": [
"cpe:2.3:a:lodash:lodash-amd:*:*:*:*:*:node.js:*:*"
],
"lodash-es": [
"cpe:2.3:a:lodash:lodash-es:*:*:*:*:*:node.js:*:*"
],
"lodash.template": [
"cpe:2.3:a:lodash:lodash.template:*:*:*:*:*:node.js:*:*"
],
"lodash.unset": [
"cpe:2.3:a:lodash:lodash.unset:*:*:*:*:*:node.js:*:*"
],
"log4js": [
"cpe:2.3:a:log4js_project:log4js:*:*:*:*:*:node.js:*:*"
],
@@ -4235,6 +4329,9 @@
"materialize-css": [
"cpe:2.3:a:materializecss:materialize:*:*:*:*:*:*:node.js:*"
],
"mathjs": [
"cpe:2.3:a:mathjs:mathjs:*:*:*:*:*:node.js:*:*"
],
"matrix-appservice-bridge": [
"cpe:2.3:a:matrix:matrix-appservice-bridge:*:*:*:*:*:node.js:*:*"
],
@@ -4377,6 +4474,9 @@
"mpath": [
"cpe:2.3:a:mpath_project:mpath:*:*:*:*:*:node.js:*:*"
],
"mppx": [
"cpe:2.3:a:wevm:mppx:*:*:*:*:*:node.js:*:*"
],
"mqtt-packet": [
"cpe:2.3:a:mqtt-packet_project:mqtt-packet:*:*:*:*:*:node.js:*:*"
],
@@ -4443,6 +4543,9 @@
"nanoid": [
"cpe:2.3:a:nanoid_project:nanoid:*:*:*:*:*:node.js:*:*"
],
"nanotar": [
"cpe:2.3:a:unjs:nanotar:*:*:*:*:*:node.js:*:*"
],
"napi-postinstall": [
"cpe:2.3:a:un-ts:napi-postinstall:*:*:*:*:*:node.js:*:*"
],
@@ -4739,6 +4842,9 @@
"open-graph": [
"cpe:2.3:a:open-graph_project:open-graph:*:*:*:*:*:node.js:*:*"
],
"openclaw": [
"cpe:2.3:a:openclaw:openclaw:*:*:*:*:*:node.js:*:*"
],
"opencv": [
"cpe:2.3:a:node-opencv_project:node-opencv:*:*:*:*:*:node.js:*:*"
],
@@ -4802,6 +4908,9 @@
"parsejson": [
"cpe:2.3:a:parsejson_project:parsejson:*:*:*:*:*:node.js:*:*"
],
"parsoid": [
"cpe:2.3:a:wikimedia:parsoid:*:*:*:*:*:node.js:*:*"
],
"passport": [
"cpe:2.3:a:passport_project:passport:*:*:*:*:*:node.js:*:*"
],
@@ -4817,6 +4926,9 @@
"path-parse": [
"cpe:2.3:a:path-parse_project:path-parse:*:*:*:*:*:node.js:*:*"
],
"path-to-regexp": [
"cpe:2.3:a:pillarjs:path-to-regexp:*:*:*:*:*:node.js:*:*"
],
"pathval": [
"cpe:2.3:a:chaijis:pathval:*:*:*:*:*:node.js:*:*"
],
@@ -5109,6 +5221,9 @@
"robot-js": [
"cpe:2.3:a:getrobot:robot-js:*:*:*:*:*:node.js:*:*"
],
"rollup": [
"cpe:2.3:a:rollupjs:rollup:*:*:*:*:*:node.js:*:*"
],
"rollup-plugin-dev-server": [
"cpe:2.3:a:rollup-plugin-dev-server_project:rollup-plugin-dev-server:*:*:*:*:*:node.js:*:*"
],
@@ -5130,6 +5245,9 @@
"rtcmulticonnection-client": [
"cpe:2.3:a:rtcmulticonnection-client_project:rtcmulticonnection-client:*:*:*:*:*:node.js:*:*"
],
"rwsdk": [
"cpe:2.3:a:redwoodjs:redwoodsdk:*:*:*:*:*:*:*:*"
],
"s3-uploader": [
"cpe:2.3:a:s3-uploader_project:s3-uploader:*:*:*:*:*:node.js:*:*"
],
@@ -5381,6 +5499,9 @@
"sockjs": [
"cpe:2.3:a:sockjs_project:sockjs:*:*:*:*:*:node.js:*:*"
],
"spin.js": [
"cpe:2.3:a:spin.js:spin.js:*:*:*:*:*:node.js:*:*"
],
"split-html-to-chars": [
"cpe:2.3:a:split-html-to-chars_project:split-html-to-chars:*:*:*:*:*:node.js:*:*"
],
@@ -5702,6 +5823,9 @@
"utils-extend": [
"cpe:2.3:a:utils-extend_project:utils-extend:*:*:*:*:*:node.js:*:*"
],
"uuid": [
"cpe:2.3:a:uuidjs:uuid:*:*:*:*:*:node.js:*:*"
],
"uv-tj-demo": [
"cpe:2.3:a:uv-tj-demo_project:uv-tj-demo:*:*:*:*:*:node.js:*:*"
],
@@ -5981,6 +6105,9 @@
"Flask-Caching": [
"cpe:2.3:a:flask-caching_project:flask-caching:*:*:*:*:*:flask:*:*"
],
"Flask-HTTPAuth": [
"cpe:2.3:a:miguelgrinberg:flask-httpauth:*:*:*:*:*:python:*:*"
],
"Flask-Security-Too": [
"cpe:2.3:a:flask-security-too_project:flask-security-too:*:*:*:*:*:*:*:*"
],
@@ -6020,6 +6147,9 @@
"aiohttp-session": [
"cpe:2.3:a:aio-libs:aiohttp_session:*:*:*:*:*:*:*:*"
],
"ajenti.plugin.core": [
"cpe:2.3:a:ajenti:ajenti_plugin_core:*:*:*:*:*:*:*:*"
],
"aniso8601": [
"cpe:2.3:a:aniso8601_project:aniso8601:*:*:*:*:*:*:*:*"
],
@@ -6068,6 +6198,9 @@
"certifi": [
"cpe:2.3:a:certifi:certifi:*:*:*:*:*:python:*:*"
],
"claude-agent-sdk": [
"cpe:2.3:a:anthropic:claude_agent_sdk:*:*:*:*:*:python:*:*"
],
"cleo": [
"cpe:2.3:a:python-poetry:cleo:*:*:*:*:*:*:*:*"
],
@@ -6093,6 +6226,9 @@
"cpe:2.3:a:cryptography.io:cryptography:*:*:*:*:*:*:*:*",
"cpe:2.3:a:cryptography.io:cryptography:*:*:*:*:*:python:*:*"
],
"curl-cffi": [
"cpe:2.3:a:lexiforest:curl_cffi:*:*:*:*:*:python:*:*"
],
"cvxopt": [
"cpe:2.3:a:cvxopt_project:cvxopt:*:*:*:*:*:python:*:*"
],
@@ -6126,6 +6262,9 @@
"django-user-sessions": [
"cpe:2.3:a:django-user-sessions_project:django-user-sessions:*:*:*:*:*:*:*:*"
],
"docling-core": [
"cpe:2.3:a:docling:docling-core:*:*:*:*:*:python:*:*"
],
"drf-jwt": [
"cpe:2.3:a:styria:django-rest-framework-json_web_tokens:*:*:*:*:*:*:*:*"
],
@@ -6144,6 +6283,9 @@
"ecdsa": [
"cpe:2.3:a:tlsfuzzer:ecdsa:*:*:*:*:*:python:*:*"
],
"emmett": [
"cpe:2.3:a:emmett:emmett:*:*:*:*:*:*:*:*"
],
"enum34": [
"cpe:2.3:a:python:enum34:*:*:*:*:*:*:*:*"
],
@@ -6156,6 +6298,9 @@
"fastapi-api-key": [
"cpe:2.3:a:athroniaeth:fastapi_api_key:*:*:*:*:*:python:*:*"
],
"fastfeedparser": [
"cpe:2.3:a:kagi:fastfeedparser:*:*:*:*:*:python:*:*"
],
"feedgen": [
"cpe:2.3:a:feedgen_project:feedgen:*:*:*:*:*:python:*:*"
],
@@ -6217,6 +6362,9 @@
"jwcrypto": [
"cpe:2.3:a:latchset:jwcrypto:*:*:*:*:*:*:*:*"
],
"kedro": [
"cpe:2.3:a:linuxfoundation:kedro:*:*:*:*:*:python:*:*"
],
"keep": [
"cpe:2.3:a:keep_project:keep:*:*:*:*:*:*:*:*"
],
@@ -6232,9 +6380,15 @@
"langchain-experimental": [
"cpe:2.3:a:langchain:langchain_experimental:*:*:*:*:*:python:*:*"
],
"lerobot": [
"cpe:2.3:a:huggingface:lerobot:*:*:*:*:*:python:*:*"
],
"loguru": [
"cpe:2.3:a:loguru_project:loguru:*:*:*:*:*:python:*:*"
],
"lupa": [
"cpe:2.3:a:scoder:lupa:*:*:*:*:*:python:*:*"
],
"lxml": [
"cpe:2.3:a:lxml:lxml:*:*:*:*:*:*:*:*"
],
@@ -6247,6 +6401,12 @@
"mage-ai": [
"cpe:2.3:a:mage:mage-ai:*:*:*:*:*:python:*:*"
],
"magic-wormhole": [
"cpe:2.3:a:magic_wormhole_project:magic_wormhole:*:*:*:*:*:python:*:*"
],
"marimo": [
"cpe:2.3:a:coreweave:marimo:*:*:*:*:*:python:*:*"
],
"marshmallow": [
"cpe:2.3:a:marshmallow_project:marshmallow:*:*:*:*:*:python:*:*"
],
@@ -6274,6 +6434,9 @@
"oncall": [
"cpe:2.3:a:linkedin:oncall:*:*:*:*:*:*:*:*"
],
"onnx": [
"cpe:2.3:a:linuxfoundation:onnx:*:*:*:*:*:*:*:*"
],
"openapi-python-client": [
"cpe:2.3:a:openapi-python-client_project:openapi-python-client:*:*:*:*:*:*:*:*"
],
@@ -6307,9 +6470,15 @@
"pdm": [
"cpe:2.3:a:frostming:pdm:*:*:*:*:*:python:*:*"
],
"picklescan": [
"cpe:2.3:a:mmaitre314:picklescan:*:*:*:*:*:*:*:*"
],
"pillow-heif": [
"cpe:2.3:a:bigcat88:pillow-heif:*:*:*:*:*:python:*:*"
],
"pipecat-ai": [
"cpe:2.3:a:pipecat:pipecat:*:*:*:*:*:python:*:*"
],
"pipreqs": [
"cpe:2.3:a:pipreqs_project:pipreqs:*:*:*:*:*:python:*:*"
],
@@ -6319,6 +6488,9 @@
"poetry": [
"cpe:2.3:a:python-poetry:poetry:*:*:*:*:*:python:*:*"
],
"praisonaiagents": [
"cpe:2.3:a:praison:praisonaiagents:*:*:*:*:*:python:*:*"
],
"pretix": [
"cpe:2.3:a:rami:pretix:*:*:*:*:*:*:*:*"
],
@@ -6367,6 +6539,9 @@
"pydash": [
"cpe:2.3:a:derrickgilland:pydash:*:*:*:*:*:python:*:*"
],
"pydicom": [
"cpe:2.3:a:pydicom:pydicom:*:*:*:*:*:python:*:*"
],
"pyesasky": [
"cpe:2.3:a:esa:pyesasky:*:*:*:*:*:python:*:*"
],
@@ -6391,6 +6566,9 @@
"pypolicyd-spf": [
"cpe:2.3:a:pypolicyd-spf_project:pypolicyd-spf:*:*:*:*:*:*:*:*"
],
"python-dotenv": [
"cpe:2.3:a:saurabh-kumar:python-dotenv:*:*:*:*:*:python:*:*"
],
"python-gnupg": [
"cpe:2.3:a:python:python-gnupg:*:*:*:*:*:*:*:*"
],
@@ -6463,6 +6641,9 @@
"setuptools": [
"cpe:2.3:a:python:setuptools:*:*:*:*:*:*:*:*"
],
"sigstore": [
"cpe:2.3:a:linuxfoundation:sigstore-python:*:*:*:*:*:*:*:*"
],
"simiki": [
"cpe:2.3:a:simiki_project:simiki:*:*:*:*:*:*:*:*"
],
@@ -6490,12 +6671,18 @@
"starlette": [
"cpe:2.3:a:encode:starlette:*:*:*:*:*:python:*:*"
],
"strawberry-graphql": [
"cpe:2.3:a:strawberry:strawberry_graphql:*:*:*:*:*:python:*:*"
],
"tablib": [
"cpe:2.3:a:python:tablib:*:*:*:*:*:*:*:*"
],
"taguette": [
"cpe:2.3:a:taguette:taguette:*:*:*:*:*:*:*:*"
],
"telnyx": [
"cpe:2.3:a:telnyx:telnyx:*:*:*:*:*:python:*:*"
],
"tkvideoplayer": [
"cpe:2.3:a:python:tkvideoplayer:*:*:*:*:*:*:*:*"
],
@@ -6511,6 +6698,9 @@
"unearth": [
"cpe:2.3:a:frostming:unearth:*:*:*:*:*:python:*:*"
],
"unstructured": [
"cpe:2.3:a:unstructured:unstructured:*:*:*:*:*:python:*:*"
],
"untangle": [
"cpe:2.3:a:untangle_project:untangle:*:*:*:*:*:python:*:*"
],
@@ -6585,6 +6775,12 @@
"bson": [
"cpe:2.3:a:bson_project:bson:*:*:*:*:*:ruby:*:*"
],
"bsv-sdk": [
"cpe:2.3:a:sgbett:bsv_ruby_sdk:*:*:*:*:*:ruby:*:*"
],
"bsv-wallet": [
"cpe:2.3:a:sgbett:bsv-wallet:*:*:*:*:*:ruby:*:*"
],
"cap-strap": [
"cpe:2.3:a:cap-strap_project:cap-strap:*:*:*:*:*:ruby:*:*"
],
@@ -6718,11 +6914,15 @@
"httparty": [
"cpe:2.3:a:jnunemaker:httparty:*:*:*:*:*:ruby:*:*"
],
"icalendar": [
"cpe:2.3:a:icalendar_project:icalendar:*:*:*:*:*:ruby:*:*"
],
"iodine": [
"cpe:2.3:a:boazsegev:iodine:*:*:*:*:*:ruby:*:*"
],
"json": [
"cpe:2.3:a:json_project:json:*:*:*:*:*:ruby:*:*"
"cpe:2.3:a:json_project:json:*:*:*:*:*:ruby:*:*",
"cpe:2.3:a:ruby-lang:json:*:*:*:*:*:ruby:*:*"
],
"json-jwt": [
"cpe:2.3:a:json-jwt_project:json-jwt:*:*:*:*:*:ruby:*:*"
@@ -6754,12 +6954,18 @@
"lean-ruport": [
"cpe:2.3:a:lean-ruport_project:lean-ruport:*:*:*:*:*:ruby:*:*"
],
"lodash-rails": [
"cpe:2.3:a:lodash:lodash-rails:*:*:*:*:*:ruby:*:*"
],
"loofah": [
"cpe:2.3:a:loofah_project:loofah:*:*:*:*:*:ruby:*:*"
],
"lynx": [
"cpe:2.3:a:lynx_project:lynx:*:*:*:*:*:ruby:*:*"
],
"mcp": [
"cpe:2.3:a:lfprojects:mcp_ruby_sdk:*:*:*:*:*:*:*:*"
],
"mechanize": [
"cpe:2.3:a:mechanize_project:mechanize:*:*:*:*:*:ruby:*:*"
],
@@ -7189,6 +7395,9 @@
"containers": [
"cpe:2.3:a:containers_project:containers:*:*:*:*:*:rust:*:*"
],
"coreutils": [
"cpe:2.3:a:uutils:coreutils:*:*:*:*:*:rust:*:*"
],
"cranelift-codegen": [
"cpe:2.3:a:bytecodealliance:cranelift-codegen:*:*:*:*:*:rust:*:*"
],
@@ -7264,6 +7473,9 @@
"heapless": [
"cpe:2.3:a:heapless_project:heapless:*:*:*:*:*:rust:*:*"
],
"httpsig-hyper": [
"cpe:2.3:a:junkurihara:httpsig-hyper:*:*:*:*:*:rust:*:*"
],
"ic-stable-structures": [
"cpe:2.3:a:dfinity:stable_structures:*:*:*:*:*:rust:*:*"
],
@@ -7309,6 +7521,9 @@
"libp2p-deflate": [
"cpe:2.3:a:libp2p:libp2p-deflate:*:*:*:*:*:rust:*:*"
],
"libp2p-gossipsub": [
"cpe:2.3:a:protocol:libp2p-gossipsub:*:*:*:*:*:rust:*:*"
],
"libpulse-binding": [
"cpe:2.3:a:libpulse-binding_project:libpulse-binding:*:*:*:*:*:rust:*:*"
],
@@ -7339,6 +7554,9 @@
"lucet-runtime-internals": [
"cpe:2.3:a:lucet-runtime-internals_project:lucet-runtime-internals:*:*:*:*:*:rust:*:*"
],
"lz4_flex": [
"cpe:2.3:a:pseitz:lz4_flex:*:*:*:*:*:rust:*:*"
],
"magnetic": [
"cpe:2.3:a:magnetic_project:magnetic:*:*:*:*:*:rust:*:*"
],
@@ -7480,6 +7698,9 @@
"simple_asn1": [
"cpe:2.3:a:simple_asn1_project:simple_asn1:*:*:*:*:*:rust:*:*"
],
"skim": [
"cpe:2.3:a:skim-rs:skim:*:*:*:*:*:rust:*:*"
],
"slack_morphism": [
"cpe:2.3:a:slack_morphism_project:slack_morphism:*:*:*:*:*:rust:*:*"
],
@@ -7606,6 +7827,18 @@
"zebra-consensus": [
"cpe:2.3:a:zfnd:zebra-consensus:*:*:*:*:*:rust:*:*"
],
"zebra-rpc": [
"cpe:2.3:a:zfnd:zebra-rpc:*:*:*:*:*:rust:*:*"
],
"zebra-script": [
"cpe:2.3:a:zfnd:zebra-script:*:*:*:*:*:rust:*:*"
],
"zebrad": [
"cpe:2.3:a:zfnd:zebrad:*:*:*:*:*:rust:*:*"
],
"zeptoclaw": [
"cpe:2.3:a:zeptoclaw:zeptoclaw:*:*:*:*:*:rust:*:*"
],
"zeroize_derive": [
"cpe:2.3:a:zeroize_derive_project:zeroize_derive:*:*:*:*:*:rust:*:*"
]
@@ -12356,6 +12589,9 @@
"friends": [
"cpe:2.3:a:alex.kirk:friends:*:*:*:*:*:wordpress:*:*"
],
"front-end-editor": [
"cpe:2.3:a:scribu:front-end_editor:*:*:*:*:*:wordpress:*:*"
],
"front-end-only-users": [
"cpe:2.3:a:etoilewebdesign:front_end_users:*:*:*:*:*:wordpress:*:*"
],
@@ -14098,6 +14334,10 @@
"link-to-bible": [
"cpe:2.3:a:bibleserver:link_to_bible:*:*:*:*:*:wordpress:*:*"
],
"link-whisper": [
"cpe:2.3:a:linkwhisper:link_whisper:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:linkwhisper:link_whisper:*:*:*:*:free:wordpress:*:*"
],
"linked-variation": [
"cpe:2.3:a:multidots:advanced_linked_variations_for_woocommerce:*:*:*:*:*:wordpress:*:*"
],
@@ -17243,6 +17483,9 @@
"sexy-contact-form": [
"cpe:2.3:a:creative-solutions:creative_contact_form:*:*:*:*:*:wordpress:*:*"
],
"sg-cachepress": [
"cpe:2.3:a:siteground:speed_optimizer:*:*:*:*:*:wordpress:*:*"
],
"sg-security": [
"cpe:2.3:a:siteground:security_optimizer:*:*:*:*:*:wordpress:*:*"
],
@@ -18171,6 +18414,9 @@
"sprout-invoices": [
"cpe:2.3:a:webventures:client_invoicing_by_sprout_invoices:*:*:*:*:*:wordpress:*:*"
],
"sql-chart-builder": [
"cpe:2.3:a:guaven:sql_chart_builder:*:*:*:*:*:wordpress:*:*"
],
"squeeze": [
"cpe:2.3:a:squeeze_project:squeeze:*:*:*:*:*:wordpress:*:*"
],
@@ -21864,6 +22110,9 @@
"wpshopgermany-protectedshops": [
"cpe:2.3:a:maennchen1:wpshopgermany_-_protected_shops:*:*:*:*:*:wordpress:*:*"
],
"wpshopify": [
"cpe:2.3:a:shopwp_project:shopwp:*:*:*:*:*:wordpress:*:*"
],
"wpsimpletools-log-viewer": [
"cpe:2.3:a:wpsimpletools:basic_log_viewer:*:*:*:*:*:wordpress:*:*"
],
@@ -6,9 +6,7 @@ import (
"encoding/json"
"fmt"
"io"
"maps"
"regexp"
"slices"
"strings"
"github.com/goccy/go-yaml"
@@ -25,6 +23,11 @@ import (
)
var (
// packageAliasExp matches aliased yarn dependencies and captures the
// underlying npm package name instead of the local alias.
// For example: "old-async@npm:async@0.9.2" returns "async".
packageAliasExp = regexp.MustCompile(`^"?(?:@\w[\w-_.]*\/)?\w[\w-_.]*@npm:((?:@\w[\w-_.]*\/)?\w[\w-_.]*)@`)
// packageNameExp matches the name of the dependency in yarn.lock
// including scope/namespace prefix if found.
// For example: "aws-sdk@2.706.0" returns "aws-sdk"
@@ -245,7 +248,9 @@ func parseYarnLockYaml(reader io.ReadCloser) ([]yarnPackage, error) {
return nil, fmt.Errorf("failed to unmarshal yarn v2 lockfile: %w", err)
}
packages := make(map[string]yarnPackage)
var seenPkgs = strset.New()
pkgs := []yarnPackage{}
for key, value := range lockfile {
packageName := findPackageName(key)
if packageName == "" {
@@ -253,10 +258,16 @@ func parseYarnLockYaml(reader io.ReadCloser) ([]yarnPackage, error) {
continue
}
packages[packageName] = yarnPackage{Name: packageName, Version: value.Version, Resolved: value.Resolution, Integrity: value.Checksum, Dependencies: value.Dependencies}
var pkg = yarnPackage{Name: packageName, Version: value.Version, Resolved: value.Resolution, Integrity: value.Checksum, Dependencies: value.Dependencies}
var nameVersion = pkg.Name + "@" + pkg.Version
if !seenPkgs.Has(nameVersion) {
seenPkgs.Add(nameVersion)
pkgs = append(pkgs, pkg)
}
}
return slices.Collect(maps.Values(packages)), nil
return pkgs, nil
}
func (a genericYarnLockAdapter) parseYarnLock(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
@@ -305,6 +316,9 @@ func (a genericYarnLockAdapter) parseYarnLock(ctx context.Context, resolver file
}
func findPackageName(line string) string {
if matches := packageAliasExp.FindStringSubmatch(line); len(matches) >= 2 {
return matches[1]
}
if matches := packageNameExp.FindStringSubmatch(line); len(matches) >= 2 {
return matches[1]
}
@@ -204,6 +204,42 @@ func TestParseYarnBerry(t *testing.T) {
pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships)
}
func TestParseYarnBerryWithDuplicates(t *testing.T) {
var expectedRelationships []artifact.Relationship
fixture := "testdata/yarn-berry-dups/yarn.lock"
locations := file.NewLocationSet(file.NewLocation(fixture))
expectedPkgs := []pkg.Package{
{
Name: "async",
Version: "3.2.6",
Locations: locations,
PURL: "pkg:npm/async@3.2.6",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Metadata: pkg.YarnLockEntry{
Resolved: "async@npm:3.2.6",
Integrity: "10c0/36484bb15ceddf07078688d95e27076379cc2f87b10c03b6dd8a83e89475a3c8df5848859dd06a4c95af1e4c16fc973de0171a77f18ea00be899aca2a4f85e70",
},
},
{
Name: "async",
Version: "0.9.2",
Locations: locations,
PURL: "pkg:npm/async@0.9.2",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Metadata: pkg.YarnLockEntry{
Resolved: "async@npm:0.9.2",
Integrity: "10c0/22ac816db119a9b84ac7182fa969b2cceacfcfa278c3efb0ac6a94d1210a4429e42c8cf6e704039aa7662e4ba62f26cecf039c91d41ceb91355dc9672c9b9ac1",
},
},
}
adapter := newGenericYarnLockAdapter(CatalogerConfig{})
pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships)
}
func TestParseYarnLock(t *testing.T) {
var expectedRelationships []artifact.Relationship
fixture := "testdata/yarn/yarn.lock"
@@ -708,6 +744,18 @@ func TestParseYarnFindPackageNames(t *testing.T) {
line: `"color-convert@npm:^1.9.0":`,
expected: "color-convert",
},
{
line: `"old-async@npm:async@0.9.2":`,
expected: "async",
},
{
line: `"old-foo@npm:@scope/foo@1.2.3":`,
expected: "@scope/foo",
},
{
line: `"@scope/old-foo@npm:@scope/foo@1.2.3":`,
expected: "@scope/foo",
},
{
line: `"@npmcorp/code-frame@^7.1.0", "@npmcorp/code-frame@^7.10.4":`,
expected: "@npmcorp/code-frame",
@@ -0,0 +1,20 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0
"async@npm:^3.2.3":
version: 3.2.6
resolution: "async@npm:3.2.6"
checksum: 10c0/36484bb15ceddf07078688d95e27076379cc2f87b10c03b6dd8a83e89475a3c8df5848859dd06a4c95af1e4c16fc973de0171a77f18ea00be899aca2a4f85e70
languageName: node
linkType: hard
"async@npm:0.9.2":
version: 0.9.2
resolution: "async@npm:0.9.2"
checksum: 10c0/22ac816db119a9b84ac7182fa969b2cceacfcfa278c3efb0ac6a94d1210a4429e42c8cf6e704039aa7662e4ba62f26cecf039c91d41ceb91355dc9672c9b9ac1
languageName: node
linkType: hard
+4 -1
View File
@@ -4,7 +4,7 @@ configs: # AUTO-GENERATED - config structs and their fields
kernel.LinuxKernelCatalogerConfig:
fields:
- key: CatalogModules
description: CatalogModules enables cataloging linux kernel modules (`*.ko` files) in addition to the kernel itself.
description: CatalogModules enables cataloging linux kernel modules (`*.ko` and compressed `*.ko.gz`, `*.ko.xz`, `*.ko.zst` files) in addition to the kernel itself.
app_key: linux-kernel.catalog-modules
catalogers:
- ecosystem: linux # MANUAL
@@ -36,6 +36,9 @@ catalogers:
- '**/zImage'
- '**/zImage-*'
- '**/lib/modules/**/*.ko'
- '**/lib/modules/**/*.ko.gz'
- '**/lib/modules/**/*.ko.xz'
- '**/lib/modules/**/*.ko.zst'
metadata_types: # AUTO-GENERATED
- pkg.LinuxKernel
- pkg.LinuxKernelModule
+4 -1
View File
@@ -17,7 +17,7 @@ import (
var _ pkg.Cataloger = (*linuxKernelCataloger)(nil)
type LinuxKernelCatalogerConfig struct {
// CatalogModules enables cataloging linux kernel modules (`*.ko` files) in addition to the kernel itself.
// CatalogModules enables cataloging linux kernel modules (`*.ko` and compressed `*.ko.gz`, `*.ko.xz`, `*.ko.zst` files) in addition to the kernel itself.
// app-config: linux-kernel.catalog-modules
CatalogModules bool `yaml:"catalog-modules" json:"catalog-modules" mapstructure:"catalog-modules"`
}
@@ -47,6 +47,9 @@ var kernelArchiveGlobs = []string{
var kernelModuleGlobs = []string{
"**/lib/modules/**/*.ko",
"**/lib/modules/**/*.ko.gz",
"**/lib/modules/**/*.ko.xz",
"**/lib/modules/**/*.ko.zst",
}
// NewLinuxKernelCataloger returns a new kernel files cataloger object.
@@ -3,9 +3,16 @@ package kernel
import (
"context"
"debug/elf"
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/mholt/archives"
intfile "github.com/anchore/syft/internal/file"
"github.com/anchore/syft/internal/tmpdir"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/internal/unionreader"
@@ -20,7 +27,14 @@ func parseLinuxKernelModuleFile(ctx context.Context, _ file.Resolver, _ *generic
if err != nil {
return nil, nil, fmt.Errorf("unable to get union reader for file: %w", err)
}
metadata, err := parseLinuxKernelModuleMetadata(unionReader)
moduleReader, err := decompressedModuleReader(ctx, reader.RealPath, unionReader)
if err != nil {
return nil, nil, fmt.Errorf("unable to decompress kernel module %q: %w", reader.RealPath, err)
}
defer moduleReader.Close()
metadata, err := parseLinuxKernelModuleMetadata(moduleReader)
if err != nil {
return nil, nil, fmt.Errorf("unable to parse kernel module metadata: %w", err)
}
@@ -39,6 +53,91 @@ func parseLinuxKernelModuleFile(ctx context.Context, _ file.Resolver, _ *generic
}, nil, nil
}
// decompressedModuleReader returns a UnionReader over the decompressed contents of the kernel module
// when the path indicates compression (e.g. .ko.gz, .ko.xz, .ko.zst). For plain .ko files the original
// reader is returned unchanged. ELF parsing requires random access (io.ReaderAt + io.Seeker), so
// compressed streams are spilled to a temp file rather than buffered in memory — kernel modules can be
// tens of MB decompressed and large numbers of them are scanned per cataloger run. The caller owns
// the returned reader and must Close it; the underlying reader (r) is not closed by Close on the
// passthrough path — its lifecycle is the caller's.
func decompressedModuleReader(ctx context.Context, path string, r unionreader.UnionReader) (unionreader.UnionReader, error) {
// fast path: plain .ko files don't need format sniffing
if strings.HasSuffix(path, ".ko") {
return &nopCloseUnionReader{UnionReader: r}, nil
}
format, stream, err := intfile.IdentifyArchive(ctx, path, r)
if err != nil {
if errors.Is(err, archives.NoMatch) {
return passthrough(r)
}
return nil, fmt.Errorf("unable to identify compression format: %w", err)
}
decompressor, ok := format.(archives.Decompressor)
if !ok {
// not a single-stream compressed format (e.g. a tar/zip archive); treat as a plain .ko
return passthrough(r)
}
rc, err := decompressor.OpenReader(stream)
if err != nil {
return nil, fmt.Errorf("unable to open %s decompression stream: %w", format.Extension(), err)
}
defer rc.Close()
td := tmpdir.FromContext(ctx)
if td == nil {
return nil, fmt.Errorf("no temp dir factory in context")
}
tempFile, fileCleanup, err := td.NewFile("syft-kmod-*.ko") //nolint:gocritic // cleanup outlives this function — runs from tempFileUnionReader.Close on the returned reader
if err != nil {
fileCleanup()
return nil, fmt.Errorf("unable to create temp file for decompressed kernel module: %w", err)
}
tfr := &tempFileUnionReader{File: tempFile, cleanup: fileCleanup}
if _, err := io.Copy(tempFile, rc); err != nil {
_ = tfr.Close()
return nil, fmt.Errorf("unable to write decompressed kernel module: %w", err)
}
if _, err := tempFile.Seek(0, io.SeekStart); err != nil {
_ = tfr.Close()
return nil, fmt.Errorf("unable to rewind decompressed kernel module: %w", err)
}
return tfr, nil
}
// passthrough returns the original reader rewound to offset 0. IdentifyArchive consumes bytes to
// sniff magic; we rewind explicitly so callers don't have to reason about the seeker's position.
func passthrough(r unionreader.UnionReader) (unionreader.UnionReader, error) {
if _, err := r.Seek(0, io.SeekStart); err != nil {
return nil, fmt.Errorf("unable to rewind reader after format sniff: %w", err)
}
return &nopCloseUnionReader{UnionReader: r}, nil
}
// nopCloseUnionReader wraps a UnionReader so that Close is a no-op. used on the passthrough path
// where the underlying reader's lifecycle is owned by the caller, not by us.
type nopCloseUnionReader struct {
unionreader.UnionReader
}
func (*nopCloseUnionReader) Close() error { return nil }
// tempFileUnionReader is a UnionReader backed by a temp file; Close closes the file and removes it.
type tempFileUnionReader struct {
*os.File
cleanup func()
}
func (t *tempFileUnionReader) Close() error {
err := t.File.Close()
t.cleanup()
return err
}
func parseLinuxKernelModuleMetadata(r unionreader.UnionReader) (p *pkg.LinuxKernelModule, err error) {
// filename: /lib/modules/5.15.0-1031-aws/kernel/zfs/zzstd.ko
// version: 1.4.5a
@@ -0,0 +1,285 @@
package kernel
import (
"bytes"
"compress/gzip"
"context"
"debug/elf"
"encoding/binary"
"io"
"os"
"testing"
"github.com/klauspost/compress/zstd"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ulikunitz/xz"
"github.com/anchore/syft/internal/tmpdir"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)
func testContext(t *testing.T) context.Context {
t.Helper()
td := tmpdir.FromPath(t.TempDir())
return tmpdir.WithValue(context.Background(), td)
}
// minimalKOBytes constructs a minimal ELF64 LE relocatable object with a .modinfo
// section containing the given null-terminated key=value entries.
func minimalKOBytes(entries []string) []byte {
// .modinfo section: each entry is key=value\0
var modinfo bytes.Buffer
for _, e := range entries {
modinfo.WriteString(e)
modinfo.WriteByte(0)
}
// section header string table — embeds names of all sections back-to-back, leading null required.
// offsets below index into this blob.
shstrtab := []byte("\x00.modinfo\x00.shstrtab\x00")
const (
modinfoNameOff uint32 = 1
shstrtabNameOff uint32 = 10
)
const (
ehdrSize uint64 = 64
shdrSize uint64 = 64
numSections uint16 = 3 // null + .modinfo + .shstrtab
)
// layout: [ehdr][modinfo][shstrtab][pad to 8][section headers]
var (
modinfoOff = ehdrSize
modinfoSize = uint64(modinfo.Len())
shstrtabOff = modinfoOff + modinfoSize
shstrtabSize = uint64(len(shstrtab))
shdrsOff = alignUp(shstrtabOff+shstrtabSize, 8)
)
header := elf.Header64{
Ident: [16]byte{
0x7f, 'E', 'L', 'F',
byte(elf.ELFCLASS64),
byte(elf.ELFDATA2LSB),
byte(elf.EV_CURRENT),
},
Type: uint16(elf.ET_REL),
Machine: uint16(elf.EM_X86_64),
Version: uint32(elf.EV_CURRENT),
Shoff: shdrsOff,
Ehsize: uint16(ehdrSize),
Shentsize: uint16(shdrSize),
Shnum: numSections,
Shstrndx: numSections - 1, // .shstrtab is last
}
sections := []elf.Section64{
{}, // SHN_UNDEF
{
Name: modinfoNameOff,
Type: uint32(elf.SHT_PROGBITS),
Off: modinfoOff,
Size: modinfoSize,
Addralign: 1,
},
{
Name: shstrtabNameOff,
Type: uint32(elf.SHT_STRTAB),
Off: shstrtabOff,
Size: shstrtabSize,
Addralign: 1,
},
}
var buf bytes.Buffer
_ = binary.Write(&buf, binary.LittleEndian, header)
buf.Write(modinfo.Bytes())
buf.Write(shstrtab)
for uint64(buf.Len()) < shdrsOff {
buf.WriteByte(0)
}
for _, s := range sections {
_ = binary.Write(&buf, binary.LittleEndian, s)
}
return buf.Bytes()
}
func alignUp(v, align uint64) uint64 {
if v%align == 0 {
return v
}
return v + (align - v%align)
}
func gzCompress(data []byte) []byte {
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
_, _ = w.Write(data)
_ = w.Close()
return buf.Bytes()
}
func xzCompress(data []byte) []byte {
var buf bytes.Buffer
w, _ := xz.NewWriter(&buf)
_, _ = w.Write(data)
_ = w.Close()
return buf.Bytes()
}
func zstCompress(data []byte) []byte {
var buf bytes.Buffer
w, _ := zstd.NewWriter(&buf)
_, _ = w.Write(data)
_ = w.Close()
return buf.Bytes()
}
// makeLocationReadCloser wraps a byte slice as a file.LocationReadCloser with the given path.
func makeLocationReadCloser(path string, data []byte) file.LocationReadCloser {
return file.LocationReadCloser{
Location: file.NewVirtualLocation(path, path),
ReadCloser: io.NopCloser(bytes.NewReader(data)),
}
}
func TestParseLinuxKernelModuleFile_Compressed(t *testing.T) {
modinfo := []string{
"name=dummy_mod",
"version=1.2.3",
"vermagic=6.1.0-rc1 SMP mod_unload",
"license=GPL v2",
}
koBytes := minimalKOBytes(modinfo)
tests := []struct {
name string
path string
data []byte
wantName string
wantVer string
wantKV string // expected KernelVersion from vermagic
}{
{
name: "uncompressed .ko",
path: "/lib/modules/6.1.0-rc1/kernel/dummy_mod.ko",
data: koBytes,
wantName: "dummy_mod",
wantVer: "1.2.3",
wantKV: "6.1.0-rc1",
},
{
name: "gzip-compressed .ko.gz",
path: "/lib/modules/6.1.0-rc1/kernel/dummy_mod.ko.gz",
data: gzCompress(koBytes),
wantName: "dummy_mod",
wantVer: "1.2.3",
wantKV: "6.1.0-rc1",
},
{
name: "xz-compressed .ko.xz",
path: "/lib/modules/6.1.0-rc1/kernel/dummy_mod.ko.xz",
data: xzCompress(koBytes),
wantName: "dummy_mod",
wantVer: "1.2.3",
wantKV: "6.1.0-rc1",
},
{
name: "zstd-compressed .ko.zst",
path: "/lib/modules/6.1.0-rc1/kernel/dummy_mod.ko.zst",
data: zstCompress(koBytes),
wantName: "dummy_mod",
wantVer: "1.2.3",
wantKV: "6.1.0-rc1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reader := makeLocationReadCloser(tt.path, tt.data)
pkgs, rels, err := parseLinuxKernelModuleFile(testContext(t), nil, &generic.Environment{}, reader)
require.NoError(t, err)
require.Len(t, pkgs, 1)
assert.Empty(t, rels)
assert.Equal(t, tt.wantName, pkgs[0].Name)
assert.Equal(t, tt.wantVer, pkgs[0].Version)
meta, ok := pkgs[0].Metadata.(pkg.LinuxKernelModule)
require.True(t, ok)
assert.Equal(t, tt.wantKV, meta.KernelVersion)
})
}
}
func TestDecompressedModuleReader(t *testing.T) {
koBytes := minimalKOBytes([]string{"name=test", "vermagic=5.15.0 SMP mod_unload"})
tests := []struct {
name string
path string
data []byte
}{
{"uncompressed", "/lib/modules/5.15.0/kernel/test.ko", koBytes},
{"gz", "/lib/modules/5.15.0/kernel/test.ko.gz", gzCompress(koBytes)},
{"xz", "/lib/modules/5.15.0/kernel/test.ko.xz", xzCompress(koBytes)},
{"zst", "/lib/modules/5.15.0/kernel/test.ko.zst", zstCompress(koBytes)},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
br := bytes.NewReader(tt.data)
wrapped := struct {
io.ReadCloser
io.ReaderAt
io.Seeker
}{
ReadCloser: io.NopCloser(br),
ReaderAt: br,
Seeker: br,
}
got, err := decompressedModuleReader(testContext(t), tt.path, wrapped)
require.NoError(t, err)
require.NotNil(t, got)
t.Cleanup(func() { _ = got.Close() })
b, err := io.ReadAll(got)
require.NoError(t, err)
assert.Equal(t, koBytes, b, "decompressed bytes should match original .ko bytes")
})
}
}
func TestDecompressedModuleReader_TempFileRemovedOnClose(t *testing.T) {
koBytes := minimalKOBytes([]string{"name=test", "vermagic=5.15.0 SMP"})
data := gzCompress(koBytes)
br := bytes.NewReader(data)
wrapped := struct {
io.ReadCloser
io.ReaderAt
io.Seeker
}{
ReadCloser: io.NopCloser(br),
ReaderAt: br,
Seeker: br,
}
got, err := decompressedModuleReader(testContext(t), "/test.ko.gz", wrapped)
require.NoError(t, err)
tfr, ok := got.(*tempFileUnionReader)
require.True(t, ok, "expected compressed path to spill to a temp file")
path := tfr.File.Name()
_, err = os.Stat(path)
require.NoError(t, err, "temp file should exist before Close")
require.NoError(t, got.Close())
_, err = os.Stat(path)
assert.True(t, os.IsNotExist(err), "temp file should be removed after Close, got err=%v", err)
}
+5 -2
View File
@@ -63,8 +63,11 @@ func parseRockspecBlock(data []byte, i *int, locals map[string]string) ([]rocksp
parsing.SkipWhitespace(data, i)
if *i >= len(data) && len(out) > 0 {
return nil, fmt.Errorf("unexpected end of block at %d", *i)
if *i >= len(data) {
if len(out) > 0 {
return nil, fmt.Errorf("unexpected end of block at %d", *i)
}
return out, nil
}
c := data[*i]
@@ -14,6 +14,17 @@ func Test_parseRockspecData(t *testing.T) {
content string
wantErr require.ErrorAssertionFunc
}{
{
name: "empty file",
content: ``,
},
{
name: "whitespace only",
content: `
`,
},
{
name: "basic valid content",
content: `
@@ -73,63 +73,63 @@ func Test_InterpreterCataloger(t *testing.T) {
fixture: "image-apache",
expectedPkgs: []string{
// interpreters
"libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
// extensions
"calendar @ 8.2.30 (/usr/lib/php/20220829/calendar.so)",
"ctype @ 8.2.30 (/usr/lib/php/20220829/ctype.so)",
"exif @ 8.2.30 (/usr/lib/php/20220829/exif.so)",
"ffi @ 8.2.30 (/usr/lib/php/20220829/ffi.so)",
"fileinfo @ 8.2.30 (/usr/lib/php/20220829/fileinfo.so)",
"ftp @ 8.2.30 (/usr/lib/php/20220829/ftp.so)",
"gettext @ 8.2.30 (/usr/lib/php/20220829/gettext.so)",
"iconv @ 8.2.30 (/usr/lib/php/20220829/iconv.so)",
"mysqli @ 8.2.30 (/usr/lib/php/20220829/mysqli.so)",
"opcache @ 8.2.30 (/usr/lib/php/20220829/opcache.so)",
"pdo @ 8.2.30 (/usr/lib/php/20220829/pdo.so)",
"pdo_mysql @ 8.2.30 (/usr/lib/php/20220829/pdo_mysql.so)",
"phar @ 8.2.30 (/usr/lib/php/20220829/phar.so)",
"posix @ 8.2.30 (/usr/lib/php/20220829/posix.so)",
"readline @ 8.2.30 (/usr/lib/php/20220829/readline.so)",
"shmop @ 8.2.30 (/usr/lib/php/20220829/shmop.so)",
"simplexml @ 8.2.30 (/usr/lib/php/20220829/simplexml.so)",
"sockets @ 8.2.30 (/usr/lib/php/20220829/sockets.so)",
"sysvmsg @ 8.2.30 (/usr/lib/php/20220829/sysvmsg.so)",
"sysvsem @ 8.2.30 (/usr/lib/php/20220829/sysvsem.so)",
"sysvshm @ 8.2.30 (/usr/lib/php/20220829/sysvshm.so)",
"tokenizer @ 8.2.30 (/usr/lib/php/20220829/tokenizer.so)",
"xml @ 8.2.30 (/usr/lib/php/20220829/xml.so)",
"xmlreader @ 8.2.30 (/usr/lib/php/20220829/xmlreader.so)",
"xmlwriter @ 8.2.30 (/usr/lib/php/20220829/xmlwriter.so)",
"xsl @ 8.2.30 (/usr/lib/php/20220829/xsl.so)",
"calendar @ 8.2.31 (/usr/lib/php/20220829/calendar.so)",
"ctype @ 8.2.31 (/usr/lib/php/20220829/ctype.so)",
"exif @ 8.2.31 (/usr/lib/php/20220829/exif.so)",
"ffi @ 8.2.31 (/usr/lib/php/20220829/ffi.so)",
"fileinfo @ 8.2.31 (/usr/lib/php/20220829/fileinfo.so)",
"ftp @ 8.2.31 (/usr/lib/php/20220829/ftp.so)",
"gettext @ 8.2.31 (/usr/lib/php/20220829/gettext.so)",
"iconv @ 8.2.31 (/usr/lib/php/20220829/iconv.so)",
"mysqli @ 8.2.31 (/usr/lib/php/20220829/mysqli.so)",
"opcache @ 8.2.31 (/usr/lib/php/20220829/opcache.so)",
"pdo @ 8.2.31 (/usr/lib/php/20220829/pdo.so)",
"pdo_mysql @ 8.2.31 (/usr/lib/php/20220829/pdo_mysql.so)",
"phar @ 8.2.31 (/usr/lib/php/20220829/phar.so)",
"posix @ 8.2.31 (/usr/lib/php/20220829/posix.so)",
"readline @ 8.2.31 (/usr/lib/php/20220829/readline.so)",
"shmop @ 8.2.31 (/usr/lib/php/20220829/shmop.so)",
"simplexml @ 8.2.31 (/usr/lib/php/20220829/simplexml.so)",
"sockets @ 8.2.31 (/usr/lib/php/20220829/sockets.so)",
"sysvmsg @ 8.2.31 (/usr/lib/php/20220829/sysvmsg.so)",
"sysvsem @ 8.2.31 (/usr/lib/php/20220829/sysvsem.so)",
"sysvshm @ 8.2.31 (/usr/lib/php/20220829/sysvshm.so)",
"tokenizer @ 8.2.31 (/usr/lib/php/20220829/tokenizer.so)",
"xml @ 8.2.31 (/usr/lib/php/20220829/xml.so)",
"xmlreader @ 8.2.31 (/usr/lib/php/20220829/xmlreader.so)",
"xmlwriter @ 8.2.31 (/usr/lib/php/20220829/xmlwriter.so)",
"xsl @ 8.2.31 (/usr/lib/php/20220829/xsl.so)",
},
expectedRels: []string{
"calendar @ 8.2.30 (/usr/lib/php/20220829/calendar.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"ctype @ 8.2.30 (/usr/lib/php/20220829/ctype.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"exif @ 8.2.30 (/usr/lib/php/20220829/exif.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"ffi @ 8.2.30 (/usr/lib/php/20220829/ffi.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"fileinfo @ 8.2.30 (/usr/lib/php/20220829/fileinfo.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"ftp @ 8.2.30 (/usr/lib/php/20220829/ftp.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"gettext @ 8.2.30 (/usr/lib/php/20220829/gettext.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"iconv @ 8.2.30 (/usr/lib/php/20220829/iconv.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"mysqli @ 8.2.30 (/usr/lib/php/20220829/mysqli.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"opcache @ 8.2.30 (/usr/lib/php/20220829/opcache.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"pdo @ 8.2.30 (/usr/lib/php/20220829/pdo.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"pdo_mysql @ 8.2.30 (/usr/lib/php/20220829/pdo_mysql.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"phar @ 8.2.30 (/usr/lib/php/20220829/phar.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"posix @ 8.2.30 (/usr/lib/php/20220829/posix.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"readline @ 8.2.30 (/usr/lib/php/20220829/readline.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"shmop @ 8.2.30 (/usr/lib/php/20220829/shmop.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"simplexml @ 8.2.30 (/usr/lib/php/20220829/simplexml.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"sockets @ 8.2.30 (/usr/lib/php/20220829/sockets.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"sysvmsg @ 8.2.30 (/usr/lib/php/20220829/sysvmsg.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"sysvsem @ 8.2.30 (/usr/lib/php/20220829/sysvsem.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"sysvshm @ 8.2.30 (/usr/lib/php/20220829/sysvshm.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"tokenizer @ 8.2.30 (/usr/lib/php/20220829/tokenizer.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"xml @ 8.2.30 (/usr/lib/php/20220829/xml.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"xmlreader @ 8.2.30 (/usr/lib/php/20220829/xmlreader.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"xmlwriter @ 8.2.30 (/usr/lib/php/20220829/xmlwriter.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"xsl @ 8.2.30 (/usr/lib/php/20220829/xsl.so) [dependency-of] libphp @ 8.2.30 (/usr/lib/apache2/modules/libphp8.2.so)",
"calendar @ 8.2.31 (/usr/lib/php/20220829/calendar.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"ctype @ 8.2.31 (/usr/lib/php/20220829/ctype.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"exif @ 8.2.31 (/usr/lib/php/20220829/exif.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"ffi @ 8.2.31 (/usr/lib/php/20220829/ffi.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"fileinfo @ 8.2.31 (/usr/lib/php/20220829/fileinfo.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"ftp @ 8.2.31 (/usr/lib/php/20220829/ftp.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"gettext @ 8.2.31 (/usr/lib/php/20220829/gettext.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"iconv @ 8.2.31 (/usr/lib/php/20220829/iconv.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"mysqli @ 8.2.31 (/usr/lib/php/20220829/mysqli.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"opcache @ 8.2.31 (/usr/lib/php/20220829/opcache.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"pdo @ 8.2.31 (/usr/lib/php/20220829/pdo.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"pdo_mysql @ 8.2.31 (/usr/lib/php/20220829/pdo_mysql.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"phar @ 8.2.31 (/usr/lib/php/20220829/phar.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"posix @ 8.2.31 (/usr/lib/php/20220829/posix.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"readline @ 8.2.31 (/usr/lib/php/20220829/readline.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"shmop @ 8.2.31 (/usr/lib/php/20220829/shmop.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"simplexml @ 8.2.31 (/usr/lib/php/20220829/simplexml.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"sockets @ 8.2.31 (/usr/lib/php/20220829/sockets.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"sysvmsg @ 8.2.31 (/usr/lib/php/20220829/sysvmsg.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"sysvsem @ 8.2.31 (/usr/lib/php/20220829/sysvsem.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"sysvshm @ 8.2.31 (/usr/lib/php/20220829/sysvshm.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"tokenizer @ 8.2.31 (/usr/lib/php/20220829/tokenizer.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"xml @ 8.2.31 (/usr/lib/php/20220829/xml.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"xmlreader @ 8.2.31 (/usr/lib/php/20220829/xmlreader.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"xmlwriter @ 8.2.31 (/usr/lib/php/20220829/xmlwriter.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"xsl @ 8.2.31 (/usr/lib/php/20220829/xsl.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
},
},
}
+8 -1
View File
@@ -1,6 +1,13 @@
FROM --platform=linux/amd64 httpd:2.4.63-bookworm AS builder
RUN apt update -y && apt install -y libapache2-mod-php php8.2-memcache php8.2-memcache php8.2-xml php8.2-mysqli php8.2-opcache
# pin php8.2 packages to avoid version drift when debian publishes security updates
ARG PHP_VERSION=8.2.31-1~deb12u1
RUN apt update -y && apt install -y \
libapache2-mod-php8.2=${PHP_VERSION} \
php8.2-common=${PHP_VERSION} \
php8.2-xml=${PHP_VERSION} \
php8.2-mysql=${PHP_VERSION} \
php8.2-opcache=${PHP_VERSION}
FROM busybox:latest
@@ -170,8 +170,8 @@ func (rp requirementsParser) parseRequirementsTxt(ctx context.Context, _ file.Re
}
func parseVersion(version string, guessFromConstraint bool) string {
if isPinnedConstraint(version) {
return strings.TrimSpace(strings.ReplaceAll(version, "==", ""))
if version := parsePinnedVersion(version); version != "" {
return version
}
if guessFromConstraint {
@@ -181,15 +181,26 @@ func parseVersion(version string, guessFromConstraint bool) string {
return ""
}
func isPinnedConstraint(version string) bool {
return strings.Contains(version, "==") && !strings.ContainsAny(version, "*,<>!")
func parsePinnedVersion(version string) string {
version = strings.TrimSpace(version)
if strings.ContainsAny(version, "*,<>!") {
return ""
}
for _, operator := range []string{"===", "=="} {
if strings.HasPrefix(version, operator) && !strings.HasPrefix(version, operator+"=") {
return strings.TrimSpace(strings.TrimPrefix(version, operator))
}
}
return ""
}
func guessVersion(constraint string) string {
// handle "2.8.*" -> "2.8.0"
constraint = strings.ReplaceAll(constraint, "*", "0")
if isPinnedConstraint(constraint) {
return strings.TrimSpace(strings.ReplaceAll(constraint, "==", ""))
if version := parsePinnedVersion(constraint); version != "" {
return version
}
constraints := strings.Split(constraint, ",")
@@ -29,6 +29,18 @@ func TestParseRequirementsTxt(t *testing.T) {
VersionConstraint: "== 4.0.0",
},
},
{
Name: "urllib3",
Version: "1.26.20",
PURL: "pkg:pypi/urllib3@1.26.20",
Locations: locations,
Language: pkg.Python,
Type: pkg.PythonPkg,
Metadata: pkg.PythonRequirementsEntry{
Name: "urllib3",
VersionConstraint: "===1.26.20",
},
},
{
Name: "foo",
Version: "1.0.0",
@@ -294,6 +306,14 @@ func Test_newRequirement(t *testing.T) {
VersionConstraint: "==2.8",
},
},
{
name: "arbitrary equality",
raw: "urllib3===1.26.20",
want: &unprocessedRequirement{
Name: "urllib3",
VersionConstraint: "===1.26.20",
},
},
{
name: "comment + constraint",
raw: "Mopidy-Dirble ~= 1.1 # Compatible release. Same as >= 1.1, == 1.*",
@@ -363,6 +383,11 @@ func Test_parseVersion(t *testing.T) {
version: " == 1.0.0 ",
want: "1.0.0",
},
{
name: "arbitrary equality constraint",
version: " === 1.26.20 ",
want: "1.26.20",
},
{
name: "resolve lowest, simple constraint",
version: " >= 1.0.0 ",
@@ -1,4 +1,5 @@
flask == 4.0.0
urllib3===1.26.20
# a line that is ignored
sqlalchemy >= 1.0.0, <= 2.0.0, != 3.0.0, <= 3.0.0
foo == 1.0.0 # a comment that needs to be ignored
+1 -1
View File
@@ -220,7 +220,7 @@ func TypeByName(name string) Type {
return CondaPkg
case packageurl.TypePub:
return DartPubPkg
case "dotnet": // here to support legacy use cases
case "dotnet", packageurl.TypeNuget: // "dotnet" is here to support legacy use cases; "nuget" is the canonical purl type
return DotnetPkg
case packageurl.TypeCocoapods:
return CocoapodsPkg
+5
View File
@@ -58,6 +58,11 @@ func TestTypeFromPURL(t *testing.T) {
purl: "pkg:dotnet/Microsoft.CodeAnalysis.Razor@2.2.0",
expected: DotnetPkg,
},
{
name: "nuget purl maps to dotnet",
purl: "pkg:nuget/Minio@7.0.0",
expected: DotnetPkg,
},
{
purl: "pkg:composer/laravel/laravel@5.5.0",
expected: PhpComposerPkg,
@@ -145,6 +145,9 @@ func GetDirectoryExclusionFunctions(root string, exclusions []string) ([]fileres
// check exclusions for supported paths, these are all relative to the "scan root"
if strings.HasPrefix(exclusion, "./") || strings.HasPrefix(exclusion, "*/") || strings.HasPrefix(exclusion, "**/") {
exclusion = strings.TrimPrefix(exclusion, "./")
// a trailing slash signals a directory but is otherwise discarded by doublestar.Match,
// causing the pattern to silently match nothing (see issue #4839)
exclusion = strings.TrimSuffix(exclusion, "/")
exclusions[idx] = root + exclusion
} else {
errors = append(errors, exclusion)
@@ -175,6 +175,18 @@ func Test_DirectorySource_Exclusions(t *testing.T) {
},
exclusions: []string{"./target"},
},
{
input: "testdata/image-simple",
desc: "exclude explicit directory with trailing slash (issue #4839)",
glob: "**",
expected: []string{
"Dockerfile",
"file-1.txt",
"file-2.txt",
//"target/really/nested/file-3.txt", // explicitly skipped
},
exclusions: []string{"./target/"},
},
{
input: "testdata/image-simple",
desc: "exclude explicit file relative to the root",
@@ -329,6 +341,14 @@ func Test_getDirectoryExclusionFunctions_crossPlatform(t *testing.T) {
finfo: file.ManualInfo{ModeValue: os.ModeDir},
walkHint: fs.SkipDir,
},
{
desc: "directory exclusion with trailing slash (issue #4839)",
root: "/usr/var",
path: "/usr/var/lib",
exclude: "./lib/",
finfo: file.ManualInfo{ModeValue: os.ModeDir},
walkHint: fs.SkipDir,
},
{
desc: "no file info",
root: "/",
@@ -92,6 +92,10 @@ run_test_case test_positive_snapshot_download_asset "linux" "ppc64le" "sbom"
run_test_case test_positive_snapshot_download_asset "linux" "ppc64le" "tar.gz"
run_test_case test_positive_snapshot_download_asset "linux" "ppc64le" "rpm"
run_test_case test_positive_snapshot_download_asset "linux" "ppc64le" "deb"
run_test_case test_positive_snapshot_download_asset "linux" "riscv64" "sbom"
run_test_case test_positive_snapshot_download_asset "linux" "riscv64" "tar.gz"
run_test_case test_positive_snapshot_download_asset "linux" "riscv64" "rpm"
run_test_case test_positive_snapshot_download_asset "linux" "riscv64" "deb"
run_test_case test_positive_snapshot_download_asset "linux" "s390x" "sbom"
run_test_case test_positive_snapshot_download_asset "linux" "s390x" "tar.gz"
run_test_case test_positive_snapshot_download_asset "linux" "s390x" "rpm"
+6
View File
@@ -43,6 +43,11 @@ test_positive_snapshot_install_asset() {
local_suffix="_power8"
fi
# note: this is a change made in goreleaser v2.4.0
if [ "${arch}" == "riscv64" ]; then
local_suffix="_rva20u64"
fi
assertFilesEqual \
"$(snapshot_dir)/${os}-build_${os}_${arch}${local_suffix}/${binary}" \
@@ -95,6 +100,7 @@ trap 'teardown_snapshot_server ${worker_pid}' EXIT
run_test_case test_positive_snapshot_install_asset "linux" "amd64" "tar.gz"
run_test_case test_positive_snapshot_install_asset "linux" "arm64" "tar.gz"
run_test_case test_positive_snapshot_install_asset "linux" "ppc64le" "tar.gz"
run_test_case test_positive_snapshot_install_asset "linux" "riscv64" "tar.gz"
run_test_case test_positive_snapshot_install_asset "linux" "s390x" "tar.gz"
run_test_case test_positive_snapshot_install_asset "darwin" "amd64" "tar.gz"
run_test_case test_positive_snapshot_install_asset "darwin" "arm64" "tar.gz"
+4
View File
@@ -14,6 +14,10 @@ ee2b1289a1e4b0de9409c3a78867949ca42788a5f50072b8a6e6e04e6a269f9c syft_1.5.0_lin
dc4b8c4a02ffd8dd394ab94695ed44ed2bfceb06bc239835c51e84dd9b84a68c syft_1.5.0_linux_ppc64le.rpm
392044f2951ca6522d0bc71de43763202a548d40bf836098caf286041a7c8fa4 syft_1.5.0_linux_ppc64le.sbom
551d98b67f7476bc2e38453a588177b0b038933850a351a94c4bf360813f01d0 syft_1.5.0_linux_ppc64le.tar.gz
98cd582d9484f428cccd7351031543038f26d4e3f1481c5916e08e65983f1e21 syft_1.5.0_linux_riscv64.deb
3a5197d43a469feaa87c723448a47a2312cf26456eef4580b59eac447baef9d4 syft_1.5.0_linux_riscv64.rpm
5805bfb3e30452c8860665ea88bfdf356e9536a35c1b8ba28ac5b4717f2e6388 syft_1.5.0_linux_riscv64.sbom
ff15f556660cc4c4279ce41e2475bffe2a0f72eb4423c21edf7380b2484fbf68 syft_1.5.0_linux_riscv64.tar.gz
98cd582d9484f428cccd7351031543038f26d4e3f1481c5916e08e65983f1e21 syft_1.5.0_linux_s390x.deb
3a5197d43a469feaa87c723448a47a2312cf26456eef4580b59eac447baef9d4 syft_1.5.0_linux_s390x.rpm
5805bfb3e30452c8860665ea88bfdf356e9536a35c1b8ba28ac5b4717f2e6388 syft_1.5.0_linux_s390x.sbom
+4
View File
@@ -14,6 +14,10 @@ a74549794fa5dac79ab9f6401ee7000db3bd9589435b302583c3ee4ca13fb8e3 syft_1.5.0_lin
dc4b8c4a02ffd8dd394ab94695ed44ed2bfceb06bc239835c51e84dd9b84a68c syft_1.5.0_linux_ppc64le.rpm
392044f2951ca6522d0bc71de43763202a548d40bf836098caf286041a7c8fa4 syft_1.5.0_linux_ppc64le.sbom
551d98b67f7476bc2e38453a588177b0b038933850a351a94c4bf360813f01d0 syft_1.5.0_linux_ppc64le.tar.gz
98cd582d9484f428cccd7351031543038f26d4e3f1481c5916e08e65983f1e21 syft_1.5.0_linux_riscv64.deb
3a5197d43a469feaa87c723448a47a2312cf26456eef4580b59eac447baef9d4 syft_1.5.0_linux_riscv64.rpm
5805bfb3e30452c8860665ea88bfdf356e9536a35c1b8ba28ac5b4717f2e6388 syft_1.5.0_linux_riscv64.sbom
ff15f556660cc4c4279ce41e2475bffe2a0f72eb4423c21edf7380b2484fbf68 syft_1.5.0_linux_riscv64.tar.gz
98cd582d9484f428cccd7351031543038f26d4e3f1481c5916e08e65983f1e21 syft_1.5.0_linux_s390x.deb
3a5197d43a469feaa87c723448a47a2312cf26456eef4580b59eac447baef9d4 syft_1.5.0_linux_s390x.rpm
5805bfb3e30452c8860665ea88bfdf356e9536a35c1b8ba28ac5b4717f2e6388 syft_1.5.0_linux_s390x.sbom