Compare commits

...
Author SHA1 Message Date
Christopher Angelo Phillips 3cffa0b7fd chore: remove execute from test fixtures (#2450)
* chore: remove execute from test fixtures

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

* chore: add back ignored file

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

---------

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-12-20 22:34:29 +00:00
anchore-actions-token-generator[bot]andspiffcs da03e981c3 chore(deps): update tools to latest versions (#2447)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2023-12-20 10:59:01 -05:00
William Murphyandhoudini91 4aa2d8c0af fix: don't panic when hackage missing in haskell stack yaml lock (#2448)
Fixes a bug where previously the haskell cataloger would panic
when parsing a stack.yaml.lock file that had an entry with an empty
hackage string.

Signed-off-by: houdini91 <mdstrauss91@gmail.com>
Signed-off-by: Will Murphy <will.murphy@anchore.com>
Co-authored-by: houdini91 <mdstrauss91@gmail.com>
2023-12-20 10:57:06 -05:00
Laurent Goderre a635d66657 Add binary classifier for the ERLang interpretter (#2417)
Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
2023-12-18 15:00:49 -05:00
Laurent Goderre 51d3cd0066 Add binary classifier for Julia lang (#2427)
Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
2023-12-18 15:00:21 -05:00
Laurent Goderre 4846639ee4 Add binary detection for PHP composer (#2432)
Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
2023-12-18 14:59:45 -05:00
dependabot[bot] 6030a69b17 chore(deps): bump actions/upload-artifact from 3.1.3 to 4.0.0 (#2433)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3.1.3 to 4.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/a8a3f3ad30e3422c9c7b888a15615d19a852ae32...c7d193f32edcb7bfad88892161225aeda64e9392)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-18 11:17:07 -05:00
anchore-actions-token-generator[bot]andwagoodman 8b9194eb81 chore(deps): update CPE dictionary index (#2442)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: wagoodman <wagoodman@users.noreply.github.com>
2023-12-18 07:01:21 -05:00
anchore-actions-token-generator[bot]andkzantow 56a1ab54d2 chore(deps): update stereoscope to 4b999b76ca8901d15bb97aef445dc94c38d11d5c (#2440)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: kzantow <kzantow@users.noreply.github.com>
2023-12-18 06:43:24 -05:00
Alex Goodman f4dd36ca9d fix syft-json test to use pretty json for snapshot testing (#2441)
without this fix, capturing fixtures will result in hard-to-read
failures in testing.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2023-12-15 17:23:21 -05:00
Alex Goodman 17c605822e refactor pkg.Collection (#2439)
- remove "catalog" references
- add a separate add() function for readability

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2023-12-15 17:11:11 -05:00
Alex Goodman 4eace4b141 refactor javascript cataloger to use configuration options when creating packages (#2438)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2023-12-15 17:11:02 -05:00
Alex Goodman 05660da8d7 use single source of truth for archive options (#2437)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2023-12-15 17:07:55 -05:00
Alex Goodman 2f378d806e fix file digest cataloger when passed coordinates (#2436)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2023-12-15 14:43:09 -05:00
dependabot[bot] b83cc8485a chore(deps): bump github.com/CycloneDX/cyclonedx-go from 0.7.2 to 0.8.0 (#2413) 2023-12-14 17:18:37 -05:00
Colm O hEigeartaigh 38a12bd91a Look for a maven version in a pom from a parent dependency management section (#2423)
Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
2023-12-14 13:15:14 -05:00
Colm O hEigeartaigh 649d152548 Parse Python licenses from LicenseExpression entry in the Wheel Metadata (#2431)
Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
2023-12-14 12:41:41 -05:00
dependabot[bot] f5d5892434 chore(deps): bump github/codeql-action from 2.22.10 to 3.22.11 (#2430)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.10 to 3.22.11.
- [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/305f6546310b9203e892c28c1484e82977f4f63d...b374143c1149a9115d881581d29b8390bbcbb59c)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-14 12:40:39 -05:00
dependabot[bot] 51831d303c chore(deps): bump modernc.org/sqlite from 1.27.0 to 1.28.0 (#2429)
Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.27.0 to 1.28.0.
- [Commits](https://gitlab.com/cznic/sqlite/compare/v1.27.0...v1.28.0)

---
updated-dependencies:
- dependency-name: modernc.org/sqlite
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-14 12:38:55 -05:00
anchore-actions-token-generator[bot]andspiffcs 09e62c3282 chore(deps): update tools to latest versions (#2428)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2023-12-14 07:31:44 -05:00
Colm O hEigeartaigh d39ef44e40 Parse Python licenses from LicenseFile entry in the Wheel Metadata (#2331)
Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
2023-12-13 17:46:56 -05:00
Wayne Starr 8bca0ac39e fix: use filepath instead of path for file source exclusions (#2411)
Signed-off-by: Wayne Starr <me@racer159.com>
2023-12-13 17:45:34 -05:00
dependabot[bot] 67dbd1fe4c chore(deps): bump github.com/charmbracelet/bubbletea (#2424)
Bumps [github.com/charmbracelet/bubbletea](https://github.com/charmbracelet/bubbletea) from 0.24.2 to 0.25.0.
- [Release notes](https://github.com/charmbracelet/bubbletea/releases)
- [Commits](https://github.com/charmbracelet/bubbletea/compare/v0.24.2...v0.25.0)

---
updated-dependencies:
- dependency-name: github.com/charmbracelet/bubbletea
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-13 12:21:22 -05:00
dependabot[bot] 402227f0b3 chore(deps): bump github.com/google/uuid from 1.4.0 to 1.5.0 (#2425)
Bumps [github.com/google/uuid](https://github.com/google/uuid) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/google/uuid/releases)
- [Changelog](https://github.com/google/uuid/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/uuid/compare/v1.4.0...v1.5.0)

---
updated-dependencies:
- dependency-name: github.com/google/uuid
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-13 11:45:04 -05:00
dependabot[bot] 2bcf825857 chore(deps): bump github/codeql-action from 2.22.9 to 2.22.10 (#2426)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.9 to 2.22.10.
- [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/c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2...305f6546310b9203e892c28c1484e82977f4f63d)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-13 11:44:41 -05:00
dependabot[bot] 9cb7c3d350 chore(deps): bump dawidd6/action-homebrew-bump-formula (#2420)
Bumps [dawidd6/action-homebrew-bump-formula](https://github.com/dawidd6/action-homebrew-bump-formula) from 3.10.0 to 3.10.1.
- [Release notes](https://github.com/dawidd6/action-homebrew-bump-formula/releases)
- [Commits](https://github.com/dawidd6/action-homebrew-bump-formula/compare/d3667e5ae14df19579e4414897498e3e88f2f458...75ed025ff3ad1d617862838b342b06d613a0ddf3)

---
updated-dependencies:
- dependency-name: dawidd6/action-homebrew-bump-formula
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-12 14:43:43 -05:00
Colm O hEigeartaigh e789e0714d feat: add the option to retrieve remote licenses for projects defined in a maven pom (#2409)
Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
2023-12-12 14:02:36 -05:00
dependabot[bot] 790ecc6f28 chore(deps): bump github/codeql-action from 2.22.8 to 2.22.9 (#2400)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.8 to 2.22.9.
- [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/407ffafae6a767df3e0230c3df91b6443ae8df75...c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-12 13:59:39 -05:00
dependabot[bot] b9462db59e chore(deps): bump github.com/saferwall/pe from 1.4.7 to 1.4.8 (#2415)
Bumps [github.com/saferwall/pe](https://github.com/saferwall/pe) from 1.4.7 to 1.4.8.
- [Release notes](https://github.com/saferwall/pe/releases)
- [Changelog](https://github.com/saferwall/pe/blob/main/CHANGELOG.md)
- [Commits](https://github.com/saferwall/pe/compare/v1.4.7...v1.4.8)

---
updated-dependencies:
- dependency-name: github.com/saferwall/pe
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-11 12:37:20 -05:00
dependabot[bot] bfad9659a8 chore(deps): bump github.com/go-git/go-git/v5 from 5.10.1 to 5.11.0 (#2414)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.10.1 to 5.11.0.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.10.1...v5.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-11 08:58:26 -05:00
dependabot[bot] b345752f49 chore(deps): bump actions/setup-go from 4.1.0 to 5.0.0 (#2401)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4.1.0 to 5.0.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/93397bea11091df50f3d7e59dc26a7711a8bcfbe...0c52d547c9bc32b1aa3301fd7a9cb496313a4491)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-11 06:38:05 -05:00
anchore-actions-token-generator[bot]andspiffcs ba9dd1d5fd chore(deps): update tools to latest versions (#2408)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2023-12-11 06:36:51 -05:00
anchore-actions-token-generator[bot]andwagoodman 68f35815d6 chore(deps): update CPE dictionary index (#2412)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: wagoodman <wagoodman@users.noreply.github.com>
2023-12-11 06:35:58 -05:00
Weston Steimel 4d4b502174 fix(java): improve identification for org.codehaus.groovy artifacts (#2404)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-08 05:02:01 -05:00
Weston Steimel ea80f94c0e fix(java): improve identification for commons-jelly artifacts (#2399)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-07 12:28:21 -05:00
Weston Steimel 2c145f70b2 fix(java): improve identification for io.minio artifacts (#2398)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-06 16:58:07 -05:00
Weston Steimel bcc7e90fcc fix(java): improve identification for com.graphql-java artifacts (#2397)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-06 18:04:43 +00:00
anchore-actions-token-generator[bot] fa1baabc05 chore(deps): update tools to latest versions (#2395) 2023-12-06 10:49:07 -05:00
Weston Steimel b5906824cb chore: enhance java purl generation integration test (#2393)
Signed-off-by: Weston Steimel <weston.steimel@anchore.com>
2023-12-06 15:31:16 +00:00
Colm O hEigeartaighandChristopher Phillips 16dee41b4b feat: add ability to retrieve remote licenses for yarn.lock (#2338)
---------

Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
2023-12-05 13:38:28 -05:00
dependabot[bot] 23778de112 chore(deps): bump anchore/sbom-action from 0.15.0 to 0.15.1 (#2392)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.0 to 0.15.1.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/fd74a6fb98a204a1ad35bbfae0122c1a302ff88b...5ecf649a417b8ae17dc8383dc32d46c03f2312df)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-05 09:48:40 -05:00
Colm O hEigeartaigh 3ba9df4ff3 Retrieve remote licenses using pom.properties when there is no pom.xml (#2315)
Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
2023-12-05 09:47:40 -05:00
Weston Steimel bbf223b2c9 fix(java): improve identification for org.apache.tapestry artifacts (#2384)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-04 11:23:40 -05:00
Weston Steimel b126276f97 fix(java): improve identification for io.ratpack artifacts (#2379)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-04 11:23:26 -05:00
Weston Steimel 40d766a257 fix(java): improve identification for org.apache.cassandra artifacts (#2386)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-01 10:51:14 -05:00
Weston Steimel 814960f65a fix(java): improve identification for org.neo4j.procedure artifacts (#2388)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-01 10:50:24 -05:00
William Murphy 13758260dd fix: bump fangs for ptr summarize fix (#2387)
Previously, pointers to primitive types in config summarization could be
printed literally (like "0x123aefef"). Pull in fangs to get the fix for
this.

Signed-off-by: Will Murphy <will.murphy@anchore.com>
2023-12-01 14:37:42 +00:00
Weston Steimel 11039f4b4e fix(java): improve identification for org.elasticsearch artifacts (#2383)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-01 09:22:33 -05:00
Weston Steimel 413ffdb233 fix(java): improve identification for org.apache.geode artifacts (#2382)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-01 12:48:15 +00:00
Weston Steimel e53fe51612 fix(java): improve identification for org.apache.tomcat.embed artifacts (#2381)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-01 07:13:13 -05:00
Weston Steimel facbc486a8 fix(java): improve identification for io.projectreactor.netty artifacts (#2378)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-12-01 07:09:06 -05:00
Weston Steimel 5d42a349e6 fix(java): improve identification for org.eclipse.platform artifacts (#2349)
Signed-off-by: Weston Steimel <weston.steimel@proton.me>
2023-11-30 16:02:03 -05:00
Alex Goodman 4adfbeb5f0 Generalize UI events for cataloging tasks (#2369)
* generalize ui events for cataloging tasks

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

* moderate review comments

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

* incorporate review comments

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

* rename cataloger task progress object

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

* migrate cataloger task fn to bus helper

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

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2023-11-30 16:25:50 +00:00
anchore-actions-token-generator[bot]andspiffcs b943da6433 chore(deps): update tools to latest versions (#2376)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2023-11-30 09:25:02 -05:00
dependabot[bot] e8119acf93 chore(deps): bump github.com/google/go-containerregistry (#2377)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.16.1 to 0.17.0.
- [Release notes](https://github.com/google/go-containerregistry/releases)
- [Changelog](https://github.com/google/go-containerregistry/blob/main/.goreleaser.yml)
- [Commits](https://github.com/google/go-containerregistry/compare/v0.16.1...v0.17.0)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-30 09:24:25 -05:00
Laurent Goderre 06b9a79e3d chore: fix tests failing due to Mac Rosetta cache (#2374)
Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
2023-11-29 18:39:28 +00:00
Keith Zantow ef5c1651ef fix: improve dotnet portable executable identification (#2133)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-11-29 12:51:24 -05:00
101 changed files with 3194 additions and 1547 deletions
+4 -4
View File
@@ -1,7 +1,7 @@
tools:
- name: binny
version:
want: v0.6.2
want: v0.6.3
method: github-release
with:
repo: anchore/binny
@@ -29,7 +29,7 @@ tools:
- name: cosign
version:
want: v2.2.1
want: v2.2.2
method: github-release
with:
repo: sigstore/cosign
@@ -83,14 +83,14 @@ tools:
- name: task
version:
want: v3.31.0
want: v3.32.0
method: github-release
with:
repo: go-task/task
- name: gh
version:
want: v2.39.2
want: v2.40.1
method: github-release
with:
repo: cli/cli
+1 -1
View File
@@ -39,7 +39,7 @@ jobs:
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
echo "result=$OUTPUT" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
- uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
with:
name: benchmark-test-results
path: test/results/**/*
+4 -4
View File
@@ -39,13 +39,13 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
- name: Install Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 #v5.0.0
with:
go-version-file: go.mod
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@407ffafae6a767df3e0230c3df91b6443ae8df75 #v2.22.8
uses: github/codeql-action/init@b374143c1149a9115d881581d29b8390bbcbb59c #v3.22.11
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -56,7 +56,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@407ffafae6a767df3e0230c3df91b6443ae8df75 #v2.22.8
uses: github/codeql-action/autobuild@b374143c1149a9115d881581d29b8390bbcbb59c #v3.22.11
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -70,4 +70,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@407ffafae6a767df3e0230c3df91b6443ae8df75 #v2.22.8
uses: github/codeql-action/analyze@b374143c1149a9115d881581d29b8390bbcbb59c #v3.22.11
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
echo -n "commit=$(git rev-parse HEAD)" | tee -a $GITHUB_OUTPUT
- name: Update Homebrew formula
uses: dawidd6/action-homebrew-bump-formula@d3667e5ae14df19579e4414897498e3e88f2f458 # v3.10.0
uses: dawidd6/action-homebrew-bump-formula@75ed025ff3ad1d617862838b342b06d613a0ddf3 # v3.10.1
with:
token: ${{ secrets.HOMEBREW_TOKEN }}
org: anchore
+1 -1
View File
@@ -141,7 +141,7 @@ jobs:
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
- uses: anchore/sbom-action@fd74a6fb98a204a1ad35bbfae0122c1a302ff88b #v0.15.0
- uses: anchore/sbom-action@5ecf649a417b8ae17dc8383dc32d46c03f2312df #v0.15.1
continue-on-error: true
with:
artifact-name: sbom.spdx.json
@@ -19,7 +19,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 #v5.0.0
with:
go-version: ${{ env.GO_VERSION }}
stable: ${{ env.GO_STABLE_VERSION }}
+5 -1
View File
@@ -121,7 +121,7 @@ syft <image> --scope all-layers
### Supported sources
Syft can generate a SBOM from a variety of sources:
Syft can generate an SBOM from a variety of sources:
```
# catalog a container image archive (from the result of `docker image save ...`, `podman save ...`, or `skopeo copy` commands)
@@ -656,6 +656,10 @@ python:
# when given an arbitrary constraint will be used (even if that version may not be available/published).
guess-unpinned-requirements: false
javascript:
search-remote-licenses: false
npm-base-url: "https://registry.npmjs.org"
file-contents:
cataloger:
# enable/disable cataloging of file contents
+5
View File
@@ -16,6 +16,7 @@ import (
"github.com/anchore/syft/syft/pkg/cataloger"
golangCataloger "github.com/anchore/syft/syft/pkg/cataloger/golang"
javaCataloger "github.com/anchore/syft/syft/pkg/cataloger/java"
javascriptCataloger "github.com/anchore/syft/syft/pkg/cataloger/javascript"
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
pythonCataloger "github.com/anchore/syft/syft/pkg/cataloger/python"
"github.com/anchore/syft/syft/source"
@@ -26,6 +27,7 @@ type Catalog struct {
Package pkg `yaml:"package" json:"package" mapstructure:"package"`
Golang golang `yaml:"golang" json:"golang" mapstructure:"golang"`
Java java `yaml:"java" json:"java" mapstructure:"java"`
Javascript javascript `yaml:"javascript" json:"javascript" mapstructure:"javascript"`
LinuxKernel linuxKernel `yaml:"linux-kernel" json:"linux-kernel" mapstructure:"linux-kernel"`
Python python `yaml:"python" json:"python" mapstructure:"python"`
FileMetadata fileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
@@ -145,6 +147,9 @@ func (cfg Catalog) ToCatalogerConfig() cataloger.Config {
IncludeUnindexedArchives: cfg.Package.SearchUnindexedArchives,
},
cfg.Java.MaxParentRecursiveDepth),
Javascript: javascriptCataloger.DefaultCatalogerConfig().
WithSearchRemoteLicenses(cfg.Javascript.SearchRemoteLicenses).
WithNpmBaseURL(cfg.Javascript.NpmBaseURL),
Python: pythonCataloger.CatalogerConfig{
GuessUnpinnedRequirements: cfg.Python.GuessUnpinnedRequirements,
},
+6
View File
@@ -0,0 +1,6 @@
package options
type javascript struct {
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
NpmBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
}
@@ -1,16 +1,24 @@
[TestHandler_handleCatalogerTaskStarted/cataloging_task_in_progress - 1]
some task title [some value]
⠙ Cataloging contents
⠙ some task title ━━━━━━━━━━━━━━━━━━━━ [some stage]
---
[TestHandler_handleCatalogerTaskStarted/cataloging_sub_task_in_progress - 1]
└── some task title [some value]
⠙ Cataloging contents
└── ⠙ some task title ━━━━━━━━━━━━━━━━━━━━ [some stage]
---
[TestHandler_handleCatalogerTaskStarted/cataloging_sub_task_complete - 1]
✔ └── some task done [some value]
⠙ Cataloging contents
└── ✔ some task done [some stage]
---
[TestHandler_handleCatalogerTaskStarted/cataloging_sub_task_complete_--_hide_stage - 1]
⠙ Cataloging contents
└── ✔ some task done
---
[TestHandler_handleCatalogerTaskStarted/cataloging_sub_task_complete_with_removal - 1]
⠙ Cataloging contents
---
+10 -3
View File
@@ -100,18 +100,21 @@ func TestHandler_handleAttestationStarted(t *testing.T) {
Height: 80,
}
models := handler.Handle(event)
models, _ := handler.Handle(event)
require.Len(t, models, 2)
t.Run("task line", func(t *testing.T) {
tsk, ok := models[0].(taskprogress.Model)
require.True(t, ok)
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
gotModel := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
Time: time.Now(),
Sequence: tsk.Sequence(),
ID: tsk.ID(),
})
got := gotModel.View()
t.Log(got)
snaps.MatchSnapshot(t, got)
})
@@ -119,11 +122,15 @@ func TestHandler_handleAttestationStarted(t *testing.T) {
t.Run("log", func(t *testing.T) {
log, ok := models[1].(attestLogFrame)
require.True(t, ok)
got := runModel(t, log, tt.iterations, attestLogFrameTickMsg{
gotModel := runModel(t, log, tt.iterations, attestLogFrameTickMsg{
Time: time.Now(),
Sequence: log.sequence,
ID: log.id,
}, log.reader.running)
got := gotModel.View()
t.Log(got)
snaps.MatchSnapshot(t, got)
})
+91 -40
View File
@@ -3,70 +3,121 @@ package ui
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/google/uuid"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/bubbly/bubbles/taskprogress"
"github.com/anchore/bubbly/bubbles/tree"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/event/monitor"
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
)
var _ progress.Stager = (*catalogerTaskStageAdapter)(nil)
// we standardize how rows are instantiated to ensure consistency in the appearance across the UI
type taskModelFactory func(title taskprogress.Title, opts ...taskprogress.Option) taskprogress.Model
type catalogerTaskStageAdapter struct {
mon *monitor.CatalogerTask
var _ tea.Model = (*catalogerTaskModel)(nil)
type catalogerTaskModel struct {
model tree.Model
modelFactory taskModelFactory
}
func newCatalogerTaskStageAdapter(mon *monitor.CatalogerTask) *catalogerTaskStageAdapter {
return &catalogerTaskStageAdapter{
mon: mon,
func newCatalogerTaskTreeModel(f taskModelFactory) *catalogerTaskModel {
t := tree.NewModel()
t.Padding = " "
t.RootsWithoutPrefix = true
return &catalogerTaskModel{
modelFactory: f,
model: t,
}
}
func (c catalogerTaskStageAdapter) Stage() string {
return c.mon.GetValue()
type newCatalogerTaskRowEvent struct {
info monitor.GenericTask
prog progress.StagedProgressable
}
func (m *Handler) handleCatalogerTaskStarted(e partybus.Event) []tea.Model {
mon, err := syftEventParsers.ParseCatalogerTaskStarted(e)
if err != nil {
log.WithFields("error", err).Warn("unable to parse event")
return nil
func (cts catalogerTaskModel) Init() tea.Cmd {
return cts.model.Init()
}
func (cts catalogerTaskModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
event, ok := msg.(newCatalogerTaskRowEvent)
if !ok {
model, cmd := cts.model.Update(msg)
cts.model = model.(tree.Model)
return cts, cmd
}
var prefix string
if mon.SubStatus {
// TODO: support list of sub-statuses, not just a single leaf
prefix = "└── "
}
info, prog := event.info, event.prog
tsk := m.newTaskProgress(
tsk := cts.modelFactory(
taskprogress.Title{
// TODO: prefix should not be part of the title, but instead a separate field that is aware of the tree structure
Default: prefix + mon.Title,
Running: prefix + mon.Title,
Success: prefix + mon.TitleOnCompletion,
Default: info.Title.Default,
Running: info.Title.WhileRunning,
Success: info.Title.OnSuccess,
},
taskprogress.WithStagedProgressable(
struct {
progress.Stager
progress.Progressable
}{
Progressable: mon.GetMonitor(),
Stager: newCatalogerTaskStageAdapter(mon),
},
),
taskprogress.WithStagedProgressable(prog),
)
// TODO: this isn't ideal since the model stays around after it is no longer needed, but it works for now
tsk.HideOnSuccess = mon.RemoveOnCompletion
tsk.HideStageOnSuccess = false
tsk.HideProgressOnSuccess = false
if info.Context != "" {
tsk.Context = []string{info.Context}
}
tsk.TitleStyle = lipgloss.NewStyle()
// TODO: this is a hack to get the spinner to not show up, but ideally the component would support making the spinner optional
tsk.Spinner.Spinner.Frames = []string{" "}
tsk.HideOnSuccess = info.HideOnSuccess
tsk.HideStageOnSuccess = info.HideStageOnSuccess
tsk.HideProgressOnSuccess = true
return []tea.Model{tsk}
if info.ParentID != "" {
tsk.TitleStyle = lipgloss.NewStyle()
}
if err := cts.model.Add(info.ParentID, info.ID, tsk); err != nil {
log.WithFields("error", err).Error("unable to add cataloger task to tree model")
}
return cts, tsk.Init()
}
func (cts catalogerTaskModel) View() string {
return cts.model.View()
}
func (m *Handler) handleCatalogerTaskStarted(e partybus.Event) ([]tea.Model, tea.Cmd) {
mon, info, err := syftEventParsers.ParseCatalogerTaskStarted(e)
if err != nil {
log.WithFields("error", err).Warn("unable to parse event")
return nil, nil
}
var models []tea.Model
// only create the new cataloger task tree once to manage all cataloger task events
m.onNewCatalogerTask.Do(func() {
models = append(models, newCatalogerTaskTreeModel(m.newTaskProgress))
})
// we need to update the cataloger task model with a new row. We should never update the model outside of the
// bubbletea update-render event loop. Instead, we return a command that will be executed by the bubbletea runtime,
// producing a message that is passed to the cataloger task model. This is the prescribed way to update models
// in bubbletea.
if info.ID == "" {
// ID is optional from the consumer perspective, but required internally
info.ID = uuid.Must(uuid.NewRandom()).String()
}
cmd := func() tea.Msg {
// this message will cause the cataloger task model to add a new row to the output based on the given task
// information and progress data.
return newCatalogerTaskRowEvent{
info: *info,
prog: mon,
}
}
return models, cmd
}
+119 -44
View File
@@ -2,19 +2,22 @@ package ui
import (
"testing"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/gkampitakis/go-snaps/snaps"
"github.com/stretchr/testify/require"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/bubbly/bubbles/taskprogress"
syftEvent "github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/monitor"
)
func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
title := monitor.Title{
Default: "some task title",
OnSuccess: "some task done",
}
tests := []struct {
name string
eventFn func(*testing.T) partybus.Event
@@ -23,99 +26,171 @@ func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
{
name: "cataloging task in progress",
eventFn: func(t *testing.T) partybus.Event {
src := &monitor.CatalogerTask{
SubStatus: false,
RemoveOnCompletion: false,
Title: "some task title",
TitleOnCompletion: "some task done",
value := &monitor.CatalogerTaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
src.SetValue("some value")
value.Manual.Add(50)
return partybus.Event{
Type: syftEvent.CatalogerTaskStarted,
Source: src,
Type: syftEvent.CatalogerTaskStarted,
Source: monitor.GenericTask{
Title: title,
HideOnSuccess: false,
HideStageOnSuccess: false,
ID: "my-id",
},
Value: value,
}
},
},
{
name: "cataloging sub task in progress",
eventFn: func(t *testing.T) partybus.Event {
src := &monitor.CatalogerTask{
SubStatus: true,
RemoveOnCompletion: false,
Title: "some task title",
TitleOnCompletion: "some task done",
value := &monitor.CatalogerTaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
src.SetValue("some value")
value.Manual.Add(50)
return partybus.Event{
Type: syftEvent.CatalogerTaskStarted,
Source: src,
Type: syftEvent.CatalogerTaskStarted,
Source: monitor.GenericTask{
Title: title,
HideOnSuccess: false,
HideStageOnSuccess: false,
ID: "my-id",
ParentID: "top-level-task",
},
Value: value,
}
},
},
{
name: "cataloging sub task complete",
eventFn: func(t *testing.T) partybus.Event {
src := &monitor.CatalogerTask{
SubStatus: true,
RemoveOnCompletion: false,
Title: "some task title",
TitleOnCompletion: "some task done",
value := &monitor.CatalogerTaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
src.SetValue("some value")
src.SetCompleted()
value.SetCompleted()
return partybus.Event{
Type: syftEvent.CatalogerTaskStarted,
Source: src,
Type: syftEvent.CatalogerTaskStarted,
Source: monitor.GenericTask{
Title: title,
HideOnSuccess: false,
HideStageOnSuccess: false,
ID: "my-id",
ParentID: "top-level-task",
},
Value: value,
}
},
},
{
name: "cataloging sub task complete -- hide stage",
eventFn: func(t *testing.T) partybus.Event {
value := &monitor.CatalogerTaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
value.SetCompleted()
return partybus.Event{
Type: syftEvent.CatalogerTaskStarted,
Source: monitor.GenericTask{
Title: title,
HideOnSuccess: false,
HideStageOnSuccess: true,
ID: "my-id",
ParentID: "top-level-task",
},
Value: value,
}
},
},
{
name: "cataloging sub task complete with removal",
eventFn: func(t *testing.T) partybus.Event {
src := &monitor.CatalogerTask{
SubStatus: true,
RemoveOnCompletion: true,
Title: "some task title",
TitleOnCompletion: "some task done",
value := &monitor.CatalogerTaskProgress{
AtomicStage: progress.NewAtomicStage("some stage"),
Manual: progress.NewManual(100),
}
src.SetValue("some value")
src.SetCompleted()
value.SetCompleted()
return partybus.Event{
Type: syftEvent.CatalogerTaskStarted,
Source: src,
Type: syftEvent.CatalogerTaskStarted,
Source: monitor.GenericTask{
Title: title,
HideOnSuccess: true,
HideStageOnSuccess: false,
ID: "my-id",
ParentID: "top-level-task",
},
Value: value,
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
event := tt.eventFn(t)
// need to be able to get the initial newCatalogerTaskRowEvent + initialize the nested taskprogress model
if tt.iterations == 0 {
tt.iterations = 2
}
e := tt.eventFn(t)
handler := New(DefaultHandlerConfig())
handler.WindowSize = tea.WindowSizeMsg{
Width: 100,
Height: 80,
}
models := handler.Handle(event)
info := monitor.GenericTask{
Title: monitor.Title{
Default: "Catalog contents",
WhileRunning: "Cataloging contents",
OnSuccess: "Cataloged contents",
},
ID: "top-level-task",
}
// note: this line / event is not under test, only needed to show a sub status
kickoffEvent := &monitor.CatalogerTaskProgress{
AtomicStage: progress.NewAtomicStage(""),
Manual: progress.NewManual(-1),
}
models, cmd := handler.Handle(
partybus.Event{
Type: syftEvent.CatalogerTaskStarted,
Source: info,
Value: progress.StagedProgressable(kickoffEvent),
},
)
require.Len(t, models, 1)
require.NotNil(t, cmd)
model := models[0]
tsk, ok := model.(taskprogress.Model)
tr, ok := model.(*catalogerTaskModel)
require.True(t, ok)
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
Time: time.Now(),
Sequence: tsk.Sequence(),
ID: tsk.ID(),
})
gotModel := runModel(t, tr, tt.iterations, cmd())
models, cmd = handler.Handle(e)
require.Len(t, models, 0)
require.NotNil(t, cmd)
gotModel = runModel(t, gotModel, tt.iterations, cmd())
got := gotModel.View()
t.Log(got)
snaps.MatchSnapshot(t, got)
})
+5 -2
View File
@@ -80,18 +80,21 @@ func TestHandler_handleFetchImage(t *testing.T) {
Height: 80,
}
models := handler.Handle(event)
models, _ := handler.Handle(event)
require.Len(t, models, 1)
model := models[0]
tsk, ok := model.(taskprogress.Model)
require.True(t, ok)
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
gotModel := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
Time: time.Now(),
Sequence: tsk.Sequence(),
ID: tsk.ID(),
})
got := gotModel.View()
t.Log(got)
snaps.MatchSnapshot(t, got)
})
@@ -1,28 +0,0 @@
package ui
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/wagoodman/go-partybus"
"github.com/anchore/bubbly/bubbles/taskprogress"
"github.com/anchore/syft/internal/log"
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
)
func (m *Handler) handleFileDigestsCatalogerStarted(e partybus.Event) []tea.Model {
prog, err := syftEventParsers.ParseFileDigestsCatalogingStarted(e)
if err != nil {
log.WithFields("error", err).Warn("unable to parse event")
return nil
}
tsk := m.newTaskProgress(
taskprogress.Title{
Default: "Catalog file digests",
Running: "Cataloging file digests",
Success: "Cataloged file digests",
}, taskprogress.WithStagedProgressable(prog),
)
return []tea.Model{tsk}
}
@@ -1,97 +0,0 @@
package ui
import (
"testing"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/gkampitakis/go-snaps/snaps"
"github.com/stretchr/testify/require"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/bubbly/bubbles/taskprogress"
syftEvent "github.com/anchore/syft/syft/event"
)
func TestHandler_handleFileDigestsCatalogerStarted(t *testing.T) {
tests := []struct {
name string
eventFn func(*testing.T) partybus.Event
iterations int
}{
{
name: "cataloging in progress",
eventFn: func(t *testing.T) partybus.Event {
prog := &progress.Manual{}
prog.SetTotal(100)
prog.Set(50)
mon := struct {
progress.Progressable
progress.Stager
}{
Progressable: prog,
Stager: &progress.Stage{
Current: "current",
},
}
return partybus.Event{
Type: syftEvent.FileDigestsCatalogerStarted,
Value: mon,
}
},
},
{
name: "cataloging complete",
eventFn: func(t *testing.T) partybus.Event {
prog := &progress.Manual{}
prog.SetTotal(100)
prog.Set(100)
prog.SetCompleted()
mon := struct {
progress.Progressable
progress.Stager
}{
Progressable: prog,
Stager: &progress.Stage{
Current: "current",
},
}
return partybus.Event{
Type: syftEvent.FileDigestsCatalogerStarted,
Value: mon,
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
event := tt.eventFn(t)
handler := New(DefaultHandlerConfig())
handler.WindowSize = tea.WindowSizeMsg{
Width: 100,
Height: 80,
}
models := handler.Handle(event)
require.Len(t, models, 1)
model := models[0]
tsk, ok := model.(taskprogress.Model)
require.True(t, ok)
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
Time: time.Now(),
Sequence: tsk.Sequence(),
ID: tsk.ID(),
})
t.Log(got)
snaps.MatchSnapshot(t, got)
})
}
}
+5 -2
View File
@@ -80,18 +80,21 @@ func TestHandler_handleFileIndexingStarted(t *testing.T) {
Height: 80,
}
models := handler.Handle(event)
models, _ := handler.Handle(event)
require.Len(t, models, 1)
model := models[0]
tsk, ok := model.(taskprogress.Model)
require.True(t, ok)
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
gotModel := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
Time: time.Now(),
Sequence: tsk.Sequence(),
ID: tsk.ID(),
})
got := gotModel.View()
t.Log(got)
snaps.MatchSnapshot(t, got)
})
@@ -1,29 +0,0 @@
package ui
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/wagoodman/go-partybus"
"github.com/anchore/bubbly/bubbles/taskprogress"
"github.com/anchore/syft/internal/log"
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
)
func (m *Handler) handleFileMetadataCatalogerStarted(e partybus.Event) []tea.Model {
prog, err := syftEventParsers.ParseFileMetadataCatalogingStarted(e)
if err != nil {
log.WithFields("error", err).Warn("unable to parse event")
return nil
}
tsk := m.newTaskProgress(
taskprogress.Title{
Default: "Catalog file metadata",
Running: "Cataloging file metadata",
Success: "Cataloged file metadata",
},
taskprogress.WithStagedProgressable(prog),
)
return []tea.Model{tsk}
}
@@ -1,97 +0,0 @@
package ui
import (
"testing"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/gkampitakis/go-snaps/snaps"
"github.com/stretchr/testify/require"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/bubbly/bubbles/taskprogress"
syftEvent "github.com/anchore/syft/syft/event"
)
func TestHandler_handleFileMetadataCatalogerStarted(t *testing.T) {
tests := []struct {
name string
eventFn func(*testing.T) partybus.Event
iterations int
}{
{
name: "cataloging in progress",
eventFn: func(t *testing.T) partybus.Event {
prog := &progress.Manual{}
prog.SetTotal(100)
prog.Set(50)
mon := struct {
progress.Progressable
progress.Stager
}{
Progressable: prog,
Stager: &progress.Stage{
Current: "current",
},
}
return partybus.Event{
Type: syftEvent.FileMetadataCatalogerStarted,
Value: mon,
}
},
},
{
name: "cataloging complete",
eventFn: func(t *testing.T) partybus.Event {
prog := &progress.Manual{}
prog.SetTotal(100)
prog.Set(100)
prog.SetCompleted()
mon := struct {
progress.Progressable
progress.Stager
}{
Progressable: prog,
Stager: &progress.Stage{
Current: "current",
},
}
return partybus.Event{
Type: syftEvent.FileMetadataCatalogerStarted,
Value: mon,
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
event := tt.eventFn(t)
handler := New(DefaultHandlerConfig())
handler.WindowSize = tea.WindowSizeMsg{
Width: 100,
Height: 80,
}
models := handler.Handle(event)
require.Len(t, models, 1)
model := models[0]
tsk, ok := model.(taskprogress.Model)
require.True(t, ok)
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
Time: time.Now(),
Sequence: tsk.Sequence(),
ID: tsk.ID(),
})
t.Log(got)
snaps.MatchSnapshot(t, got)
})
}
}
@@ -1,87 +0,0 @@
package ui
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/bubbly/bubbles/taskprogress"
"github.com/anchore/syft/internal/log"
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
"github.com/anchore/syft/syft/pkg/cataloger"
)
var _ progress.StagedProgressable = (*packageCatalogerProgressAdapter)(nil)
type packageCatalogerProgressAdapter struct {
monitor *cataloger.Monitor
monitors []progress.Monitorable
}
func newPackageCatalogerProgressAdapter(monitor *cataloger.Monitor) packageCatalogerProgressAdapter {
return packageCatalogerProgressAdapter{
monitor: monitor,
monitors: []progress.Monitorable{
monitor.FilesProcessed,
monitor.PackagesDiscovered,
},
}
}
func (p packageCatalogerProgressAdapter) Stage() string {
return fmt.Sprintf("%d packages", p.monitor.PackagesDiscovered.Current())
}
func (p packageCatalogerProgressAdapter) Current() int64 {
return p.monitor.PackagesDiscovered.Current()
}
func (p packageCatalogerProgressAdapter) Error() error {
completedMonitors := 0
for _, monitor := range p.monitors {
err := monitor.Error()
if err == nil {
continue
}
if progress.IsErrCompleted(err) {
completedMonitors++
continue
}
// something went wrong
return err
}
if completedMonitors == len(p.monitors) && len(p.monitors) > 0 {
return p.monitors[0].Error()
}
return nil
}
func (p packageCatalogerProgressAdapter) Size() int64 {
// this is an inherently unknown value (indeterminate total number of packages to discover)
return -1
}
func (m *Handler) handlePackageCatalogerStarted(e partybus.Event) []tea.Model {
monitor, err := syftEventParsers.ParsePackageCatalogerStarted(e)
if err != nil {
log.WithFields("error", err).Warn("unable to parse event")
return nil
}
tsk := m.newTaskProgress(
taskprogress.Title{
Default: "Catalog packages",
Running: "Cataloging packages",
Success: "Cataloged packages",
},
taskprogress.WithStagedProgressable(
newPackageCatalogerProgressAdapter(monitor),
),
)
tsk.HideStageOnSuccess = false
return []tea.Model{tsk}
}
@@ -1,133 +0,0 @@
package ui
import (
"testing"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/gkampitakis/go-snaps/snaps"
"github.com/stretchr/testify/require"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/bubbly/bubbles/taskprogress"
syftEvent "github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/pkg/cataloger"
)
func TestHandler_handlePackageCatalogerStarted(t *testing.T) {
tests := []struct {
name string
eventFn func(*testing.T) partybus.Event
iterations int
}{
{
name: "cataloging in progress",
eventFn: func(t *testing.T) partybus.Event {
prog := &progress.Manual{}
prog.SetTotal(100)
prog.Set(50)
mon := cataloger.Monitor{
FilesProcessed: progress.NewManual(-1),
PackagesDiscovered: prog,
}
return partybus.Event{
Type: syftEvent.PackageCatalogerStarted,
Value: mon,
}
},
},
{
name: "cataloging only files complete",
eventFn: func(t *testing.T) partybus.Event {
prog := &progress.Manual{}
prog.SetTotal(100)
prog.Set(50)
files := progress.NewManual(-1)
files.SetCompleted()
mon := cataloger.Monitor{
FilesProcessed: files,
PackagesDiscovered: prog,
}
return partybus.Event{
Type: syftEvent.PackageCatalogerStarted,
Value: mon,
}
},
},
{
name: "cataloging only packages complete",
eventFn: func(t *testing.T) partybus.Event {
prog := &progress.Manual{}
prog.SetTotal(100)
prog.Set(100)
prog.SetCompleted()
files := progress.NewManual(-1)
mon := cataloger.Monitor{
FilesProcessed: files,
PackagesDiscovered: prog,
}
return partybus.Event{
Type: syftEvent.PackageCatalogerStarted,
Value: mon,
}
},
},
{
name: "cataloging complete",
eventFn: func(t *testing.T) partybus.Event {
prog := &progress.Manual{}
prog.SetTotal(100)
prog.Set(100)
prog.SetCompleted()
files := progress.NewManual(-1)
files.SetCompleted()
mon := cataloger.Monitor{
FilesProcessed: files,
PackagesDiscovered: prog,
}
return partybus.Event{
Type: syftEvent.PackageCatalogerStarted,
Value: mon,
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
event := tt.eventFn(t)
handler := New(DefaultHandlerConfig())
handler.WindowSize = tea.WindowSizeMsg{
Width: 100,
Height: 80,
}
models := handler.Handle(event)
require.Len(t, models, 1)
model := models[0]
tsk, ok := model.(taskprogress.Model)
require.True(t, ok)
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
Time: time.Now(),
Sequence: tsk.Sequence(),
ID: tsk.ID(),
})
t.Log(got)
snaps.MatchSnapshot(t, got)
})
}
}
+5 -2
View File
@@ -98,18 +98,21 @@ func TestHandler_handleReadImage(t *testing.T) {
Height: 80,
}
models := handler.Handle(event)
models, _ := handler.Handle(event)
require.Len(t, models, 1)
model := models[0]
tsk, ok := model.(taskprogress.Model)
require.True(t, ok)
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
gotModel := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
Time: time.Now(),
Sequence: tsk.Sequence(),
ID: tsk.ID(),
})
got := gotModel.View()
t.Log(got)
snaps.MatchSnapshot(t, got)
})
+19 -13
View File
@@ -29,6 +29,8 @@ type Handler struct {
Config HandlerConfig
bubbly.EventHandler
onNewCatalogerTask *sync.Once
}
func DefaultHandlerConfig() HandlerConfig {
@@ -41,28 +43,32 @@ func New(cfg HandlerConfig) *Handler {
d := bubbly.NewEventDispatcher()
h := &Handler{
EventHandler: d,
Running: &sync.WaitGroup{},
Config: cfg,
EventHandler: d,
Running: &sync.WaitGroup{},
Config: cfg,
onNewCatalogerTask: &sync.Once{},
}
// register all supported event types with the respective handler functions
d.AddHandlers(map[partybus.EventType]bubbly.EventHandlerFn{
stereoscopeEvent.PullDockerImage: h.handlePullDockerImage,
stereoscopeEvent.PullContainerdImage: h.handlePullContainerdImage,
stereoscopeEvent.ReadImage: h.handleReadImage,
stereoscopeEvent.FetchImage: h.handleFetchImage,
syftEvent.PackageCatalogerStarted: h.handlePackageCatalogerStarted,
syftEvent.FileDigestsCatalogerStarted: h.handleFileDigestsCatalogerStarted,
syftEvent.FileMetadataCatalogerStarted: h.handleFileMetadataCatalogerStarted,
syftEvent.FileIndexingStarted: h.handleFileIndexingStarted,
syftEvent.AttestationStarted: h.handleAttestationStarted,
syftEvent.CatalogerTaskStarted: h.handleCatalogerTaskStarted,
stereoscopeEvent.PullDockerImage: simpleHandler(h.handlePullDockerImage),
stereoscopeEvent.PullContainerdImage: simpleHandler(h.handlePullContainerdImage),
stereoscopeEvent.ReadImage: simpleHandler(h.handleReadImage),
stereoscopeEvent.FetchImage: simpleHandler(h.handleFetchImage),
syftEvent.FileIndexingStarted: simpleHandler(h.handleFileIndexingStarted),
syftEvent.AttestationStarted: simpleHandler(h.handleAttestationStarted),
syftEvent.CatalogerTaskStarted: h.handleCatalogerTaskStarted,
})
return h
}
func simpleHandler(fn func(partybus.Event) []tea.Model) bubbly.EventHandlerFn {
return func(e partybus.Event) ([]tea.Model, tea.Cmd) {
return fn(e), nil
}
}
func (m *Handler) OnMessage(msg tea.Msg) {
if msg, ok := msg.(tea.WindowSizeMsg); ok {
m.WindowSize = msg
+13 -27
View File
@@ -4,12 +4,11 @@ import (
"reflect"
"sync"
"testing"
"unsafe"
tea "github.com/charmbracelet/bubbletea"
)
func runModel(t testing.TB, m tea.Model, iterations int, message tea.Msg, h ...*sync.WaitGroup) string {
func runModel(t testing.TB, m tea.Model, iterations int, message tea.Msg, h ...*sync.WaitGroup) tea.Model {
t.Helper()
if iterations == 0 {
iterations = 1
@@ -37,34 +36,21 @@ func runModel(t testing.TB, m tea.Model, iterations int, message tea.Msg, h ...*
cmd = tea.Batch(nextCmds...)
}
return m.View()
return m
}
func flatten(p tea.Msg) (msgs []tea.Msg) {
if reflect.TypeOf(p).Name() == "batchMsg" {
partials := extractBatchMessages(p)
for _, m := range partials {
msgs = append(msgs, flatten(m)...)
func flatten(ps ...tea.Msg) (msgs []tea.Msg) {
for _, p := range ps {
if bm, ok := p.(tea.BatchMsg); ok {
for _, m := range bm {
if m == nil {
continue
}
msgs = append(msgs, flatten(m())...)
}
} else {
msgs = []tea.Msg{p}
}
} else {
msgs = []tea.Msg{p}
}
return msgs
}
func extractBatchMessages(m tea.Msg) (ret []tea.Msg) {
sliceMsgType := reflect.SliceOf(reflect.TypeOf(tea.Cmd(nil)))
value := reflect.ValueOf(m) // note: this is technically unaddressable
// make our own instance that is addressable
valueCopy := reflect.New(value.Type()).Elem()
valueCopy.Set(value)
cmds := reflect.NewAt(sliceMsgType, unsafe.Pointer(valueCopy.UnsafeAddr())).Elem()
for i := 0; i < cmds.Len(); i++ {
item := cmds.Index(i)
r := item.Call(nil)
ret = append(ret, r[0].Interface().(tea.Msg))
}
return ret
}
+5 -1
View File
@@ -155,7 +155,11 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
for _, newModel := range m.handler.Handle(msg) {
models, cmd := m.handler.Handle(msg)
if cmd != nil {
cmds = append(cmds, cmd)
}
for _, newModel := range models {
if newModel == nil {
continue
}
+10 -10
View File
@@ -3,25 +3,25 @@ module github.com/anchore/syft
go 1.21.0
require (
github.com/CycloneDX/cyclonedx-go v0.7.2
github.com/CycloneDX/cyclonedx-go v0.8.0
github.com/Masterminds/semver v1.5.0
github.com/Masterminds/sprig/v3 v3.2.3
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/acobaugh/osrelease v0.1.0
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc
github.com/anchore/fangs v0.0.0-20231103141714-84c94dc43a2e
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501
github.com/anchore/stereoscope v0.0.0-20231117203853-3610f4ef3e83
github.com/anchore/stereoscope v0.0.0-20231215220732-4b999b76ca89
// we are hinting brotli to latest due to warning when installing archiver v3:
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
github.com/bmatcuk/doublestar/v4 v4.6.1
github.com/charmbracelet/bubbletea v0.24.2
github.com/charmbracelet/bubbletea v0.25.0
github.com/charmbracelet/lipgloss v0.9.1
github.com/dave/jennifer v1.7.0
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
@@ -32,12 +32,12 @@ require (
github.com/github/go-spdx/v2 v2.2.0
github.com/gkampitakis/go-snaps v0.4.12
github.com/go-git/go-billy/v5 v5.5.0
github.com/go-git/go-git/v5 v5.10.1
github.com/go-git/go-git/v5 v5.11.0
github.com/go-test/deep v1.1.0
github.com/google/go-cmp v0.6.0
github.com/google/go-containerregistry v0.16.1
github.com/google/go-containerregistry v0.17.0
github.com/google/licensecheck v0.3.1
github.com/google/uuid v1.4.0
github.com/google/uuid v1.5.0
github.com/gookit/color v1.5.4
github.com/hashicorp/go-multierror v1.1.1
github.com/iancoleman/strcase v0.3.0
@@ -53,7 +53,7 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/opencontainers/go-digest v1.0.0
github.com/pelletier/go-toml v1.9.5
github.com/saferwall/pe v1.4.7
github.com/saferwall/pe v1.4.8
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
github.com/sanity-io/litter v1.5.5
github.com/sassoftware/go-rpmutils v0.2.0
@@ -73,7 +73,7 @@ require (
golang.org/x/mod v0.14.0
golang.org/x/net v0.19.0
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.27.0
modernc.org/sqlite v1.28.0
)
require (
+20 -20
View File
@@ -58,8 +58,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CycloneDX/cyclonedx-go v0.7.2 h1:kKQ0t1dPOlugSIYVOMiMtFqeXI2wp/f5DBIdfux8gnQ=
github.com/CycloneDX/cyclonedx-go v0.7.2/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk=
github.com/CycloneDX/cyclonedx-go v0.8.0 h1:FyWVj6x6hoJrui5uRQdYZcSievw3Z32Z88uYzG/0D6M=
github.com/CycloneDX/cyclonedx-go v0.8.0/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
@@ -89,12 +89,12 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461 h1:xGu4/uMWucwWV0YV3fpFIQZ6KVfS/Wfhmma8t0s0vRo=
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461/go.mod h1:Ger02eh5NpPm2IqkPAy396HU1KlK3BhOeCljDYXySSk=
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9 h1:p0ZIe0htYOX284Y4axJaGBvXHU0VCCzLN5Wf5XbKStU=
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9/go.mod h1:3ZsFB9tzW3vl4gEiUeuSOMDnwroWxIxJelOOHUp8dSw=
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc h1:A1KFO+zZZmbNlz1+WKsCF0RKVx6XRoxsAG3lrqH9hUQ=
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc/go.mod h1:QeWvNzxsrUNxcs6haQo3OtISfXUXW0qAuiG4EQiz0GU=
github.com/anchore/fangs v0.0.0-20231103141714-84c94dc43a2e h1:O8ZubApaSl7dRzKNvyfGq9cLIPLQ5v3Iz0Y3huHKCgg=
github.com/anchore/fangs v0.0.0-20231103141714-84c94dc43a2e/go.mod h1:yPsN3NUGhU5dcBtYBa1dMNzGu1yT5ZAfSjKq9DY4aV8=
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b h1:L/djgY7ZbZ/38+wUtdkk398W3PIBJLkt1N8nU/7e47A=
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b/go.mod h1:TLcE0RE5+8oIx2/NPWem/dq1DeaMoC+fPEH7hoSzPLo=
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw=
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a/go.mod h1:ubLFmlsv8/DFUQrZwY5syT5/8Er3ugSr4rDFwHsE3hg=
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU=
@@ -107,8 +107,8 @@ github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZV
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501 h1:AV7qjwMcM4r8wFhJq3jLRztew3ywIyPTRapl2T1s9o8=
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
github.com/anchore/stereoscope v0.0.0-20231117203853-3610f4ef3e83 h1:mxGIOmj+asEm8LUkPTG3/v0hi27WIlDVjiEVsUB9eqY=
github.com/anchore/stereoscope v0.0.0-20231117203853-3610f4ef3e83/go.mod h1:GKAnytSVV1hoqB5r5Gd9M5Ph3Rzqq0zPdEJesewjC2w=
github.com/anchore/stereoscope v0.0.0-20231215220732-4b999b76ca89 h1:dymFMCwnENqLr74KQppq8zHKwOPL0M1ToYAU+KVfTew=
github.com/anchore/stereoscope v0.0.0-20231215220732-4b999b76ca89/go.mod h1:GKAnytSVV1hoqB5r5Gd9M5Ph3Rzqq0zPdEJesewjC2w=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
@@ -147,8 +147,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc=
github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY=
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
@@ -288,8 +288,8 @@ github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.10.1 h1:tu8/D8i+TWxgKpzQ3Vc43e+kkhXqtsZCKI/egajKnxk=
github.com/go-git/go-git/v5 v5.10.1/go.mod h1:uEuHjxkHap8kAl//V5F/nNWwqIYtP/402ddd05mp0wg=
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -368,8 +368,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ=
github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
github.com/google/go-containerregistry v0.17.0 h1:5p+zYs/R4VGHkhyvgWurWrpJ2hW4Vv9fQI+GzdcwXLk=
github.com/google/go-containerregistry v0.17.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs=
github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY=
@@ -397,8 +397,8 @@ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S3
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
@@ -664,8 +664,8 @@ github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUz
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/saferwall/pe v1.4.7 h1:A+G3DxX49paJ5OsxBfHKskhyDtmTjShlDmBd81IsHlQ=
github.com/saferwall/pe v1.4.7/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
github.com/saferwall/pe v1.4.8 h1:ey/L8FGBMrJ1Xh+Rltj1MAFPZ4LOQYGJqNa5B1Na6B0=
github.com/saferwall/pe v1.4.8/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
@@ -1353,8 +1353,8 @@ modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8=
modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
+17
View File
@@ -2,10 +2,12 @@ package bus
import (
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/clio"
"github.com/anchore/syft/internal/redact"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/monitor"
)
func Exit() {
@@ -33,3 +35,18 @@ func Notify(message string) {
Value: message,
})
}
func StartCatalogerTask(info monitor.GenericTask, size int64, initialStage string) *monitor.CatalogerTaskProgress {
t := &monitor.CatalogerTaskProgress{
AtomicStage: progress.NewAtomicStage(initialStage),
Manual: progress.NewManual(size),
}
Publish(partybus.Event{
Type: event.CatalogerTaskStarted,
Source: info,
Value: progress.StagedProgressable(t),
})
return t
}
+7
View File
@@ -4,3 +4,10 @@ type ArchiveSearchConfig struct {
IncludeIndexedArchives bool `yaml:"include-indexed-archives" json:"include-indexed-archives" mapstructure:"include-indexed-archives"`
IncludeUnindexedArchives bool `yaml:"include-unindexed-archives" json:"include-unindexed-archives" mapstructure:"include-unindexed-archives"`
}
func DefaultArchiveSearchConfig() ArchiveSearchConfig {
return ArchiveSearchConfig{
IncludeIndexedArchives: true,
IncludeUnindexedArchives: false,
}
}
-9
View File
@@ -14,15 +14,6 @@ const (
// Events from the syft library
// PackageCatalogerStarted is a partybus event that occurs when the package cataloging has begun
PackageCatalogerStarted partybus.EventType = typePrefix + "-package-cataloger-started-event"
// FileMetadataCatalogerStarted is a partybus event that occurs when the file metadata cataloging has begun
FileMetadataCatalogerStarted partybus.EventType = typePrefix + "-file-metadata-cataloger-started-event"
// FileDigestsCatalogerStarted is a partybus event that occurs when the file digests cataloging has begun
FileDigestsCatalogerStarted partybus.EventType = typePrefix + "-file-digests-cataloger-started-event"
// FileIndexingStarted is a partybus event that occurs when the directory resolver begins indexing a filesystem
FileIndexingStarted partybus.EventType = typePrefix + "-file-indexing-started-event"
-55
View File
@@ -1,55 +0,0 @@
package monitor
import (
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/syft/event"
)
// TODO: this should be refactored to support read-only/write-only access using idioms of the progress lib
type CatalogerTask struct {
prog *progress.Manual
// Title
Title string
// TitleOnCompletion a string to use as title when completed
TitleOnCompletion string
// SubStatus indicates this progress should be rendered as a sub-item
SubStatus bool
// RemoveOnCompletion indicates this progress line will be removed when completed
RemoveOnCompletion bool
// value is the value to display -- not public as SetValue needs to be called to initialize this progress
value string
}
func (e *CatalogerTask) init() {
e.prog = progress.NewManual(-1)
bus.Publish(partybus.Event{
Type: event.CatalogerTaskStarted,
Source: e,
})
}
func (e *CatalogerTask) SetCompleted() {
if e.prog != nil {
e.prog.SetCompleted()
}
}
func (e *CatalogerTask) SetValue(value string) {
if e.prog == nil {
e.init()
}
e.value = value
}
func (e *CatalogerTask) GetValue() string {
return e.value
}
func (e *CatalogerTask) GetMonitor() *progress.Manual {
return e.prog
}
@@ -0,0 +1,10 @@
package monitor
import (
"github.com/wagoodman/go-progress"
)
type CatalogerTaskProgress struct {
*progress.AtomicStage
*progress.Manual
}
+15 -2
View File
@@ -18,6 +18,19 @@ type Title struct {
}
type GenericTask struct {
Title Title
Context string
// required fields
Title Title
// optional format fields
HideOnSuccess bool
HideStageOnSuccess bool
// optional fields
ID string
ParentID string
Context string
}
+12 -45
View File
@@ -12,7 +12,6 @@ import (
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/monitor"
"github.com/anchore/syft/syft/pkg/cataloger"
)
type ErrBadPayload struct {
@@ -40,45 +39,6 @@ func checkEventType(actual, expected partybus.EventType) error {
return nil
}
func ParsePackageCatalogerStarted(e partybus.Event) (*cataloger.Monitor, error) {
if err := checkEventType(e.Type, event.PackageCatalogerStarted); err != nil {
return nil, err
}
monitor, ok := e.Value.(cataloger.Monitor)
if !ok {
return nil, newPayloadErr(e.Type, "Value", e.Value)
}
return &monitor, nil
}
func ParseFileMetadataCatalogingStarted(e partybus.Event) (progress.StagedProgressable, error) {
if err := checkEventType(e.Type, event.FileMetadataCatalogerStarted); err != nil {
return nil, err
}
prog, ok := e.Value.(progress.StagedProgressable)
if !ok {
return nil, newPayloadErr(e.Type, "Value", e.Value)
}
return prog, nil
}
func ParseFileDigestsCatalogingStarted(e partybus.Event) (progress.StagedProgressable, error) {
if err := checkEventType(e.Type, event.FileDigestsCatalogerStarted); err != nil {
return nil, err
}
prog, ok := e.Value.(progress.StagedProgressable)
if !ok {
return nil, newPayloadErr(e.Type, "Value", e.Value)
}
return prog, nil
}
func ParseFileIndexingStarted(e partybus.Event) (string, progress.StagedProgressable, error) {
if err := checkEventType(e.Type, event.FileIndexingStarted); err != nil {
return "", nil, err
@@ -97,17 +57,24 @@ func ParseFileIndexingStarted(e partybus.Event) (string, progress.StagedProgress
return path, prog, nil
}
func ParseCatalogerTaskStarted(e partybus.Event) (*monitor.CatalogerTask, error) {
func ParseCatalogerTaskStarted(e partybus.Event) (progress.StagedProgressable, *monitor.GenericTask, error) {
if err := checkEventType(e.Type, event.CatalogerTaskStarted); err != nil {
return nil, err
return nil, nil, err
}
source, ok := e.Source.(*monitor.CatalogerTask)
var mon progress.StagedProgressable
source, ok := e.Source.(monitor.GenericTask)
if !ok {
return nil, newPayloadErr(e.Type, "Source", e.Source)
return nil, nil, newPayloadErr(e.Type, "Source", e.Source)
}
return source, nil
mon, ok = e.Value.(progress.StagedProgressable)
if !ok {
mon = nil
}
return mon, &source, nil
}
func ParseAttestationStartedEvent(e partybus.Event) (io.Reader, progress.Progressable, *monitor.GenericTask, error) {
+24 -20
View File
@@ -3,16 +3,16 @@ package filedigest
import (
"crypto"
"errors"
"fmt"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/dustin/go-humanize"
stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/bus"
intFile "github.com/anchore/syft/internal/file"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/monitor"
"github.com/anchore/syft/syft/file"
intCataloger "github.com/anchore/syft/syft/file/cataloger/internal"
)
@@ -37,13 +37,19 @@ func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordina
locations = intCataloger.AllRegularFiles(resolver)
} else {
for _, c := range coordinates {
locations = append(locations, file.NewLocationFromCoordinates(c))
locs, err := resolver.FilesByPath(c.RealPath)
if err != nil {
return nil, fmt.Errorf("unable to get file locations for path %q: %w", c.RealPath, err)
}
locations = append(locations, locs...)
}
}
stage, prog := digestsCatalogingProgress(int64(len(locations)))
prog := digestsCatalogingProgress(int64(len(locations)))
for _, location := range locations {
stage.Current = location.RealPath
prog.Increment()
prog.AtomicStage.Set(location.Path())
result, err := i.catalogLocation(resolver, location)
if errors.Is(err, ErrUndigestableFile) {
@@ -61,8 +67,12 @@ func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordina
prog.Increment()
results[location.Coordinates] = result
}
log.Debugf("file digests cataloger processed %d files", prog.Current())
prog.AtomicStage.Set(fmt.Sprintf("%s digests", humanize.Comma(prog.Current())))
prog.SetCompleted()
return results, nil
}
@@ -91,20 +101,14 @@ func (i *Cataloger) catalogLocation(resolver file.Resolver, location file.Locati
return digests, nil
}
func digestsCatalogingProgress(locations int64) (*progress.Stage, *progress.Manual) {
stage := &progress.Stage{}
prog := progress.NewManual(locations)
bus.Publish(partybus.Event{
Type: event.FileDigestsCatalogerStarted,
Value: struct {
progress.Stager
progress.Progressable
}{
Stager: progress.Stager(stage),
Progressable: prog,
func digestsCatalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
info := monitor.GenericTask{
Title: monitor.Title{
Default: "Catalog file digests",
WhileRunning: "Cataloging file digests",
OnSuccess: "Cataloged file digests",
},
})
}
return stage, prog
return bus.StartCatalogerTask(info, locations, "")
}
@@ -160,3 +160,47 @@ func TestDigestsCataloger_MixFileTypes(t *testing.T) {
})
}
}
func TestFileDigestCataloger_GivenCoordinates(t *testing.T) {
testImage := "image-file-type-mix"
img := imagetest.GetFixtureImage(t, "docker-archive", testImage)
c := NewCataloger([]crypto.Hash{crypto.SHA256})
src, err := source.NewFromStereoscopeImageObject(img, testImage, nil)
require.NoError(t, err)
resolver, err := src.FileResolver(source.SquashedScope)
require.NoError(t, err)
tests := []struct {
path string
exists bool
expected string
}{
{
path: "/file-1.txt",
exists: true,
expected: "b089629781f05ef805b4511e93717f2ffa4c9d991771d5cbfa4b7242b4ef5fff",
},
}
for _, test := range tests {
t.Run(test.path, func(t *testing.T) {
_, ref, err := img.SquashedTree().File(stereoscopeFile.Path(test.path))
require.NoError(t, err)
l := file.NewLocationFromImage(test.path, *ref.Reference, img)
// note: an important difference between this test and the previous is that this test is using a list
// of specific coordinates to catalog
actual, err := c.Catalog(resolver, l.Coordinates)
require.NoError(t, err)
require.Len(t, actual, 1)
assert.Equal(t, test.expected, actual[l.Coordinates][0].Value, "mismatched digests")
})
}
}
+20 -21
View File
@@ -1,12 +1,13 @@
package filemetadata
import (
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"fmt"
"github.com/dustin/go-humanize"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/monitor"
"github.com/anchore/syft/syft/file"
)
@@ -20,7 +21,6 @@ func NewCataloger() *Cataloger {
func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordinates) (map[file.Coordinates]file.Metadata, error) {
results := make(map[file.Coordinates]file.Metadata)
var locations <-chan file.Location
if len(coordinates) == 0 {
locations = resolver.AllLocations()
} else {
@@ -43,36 +43,35 @@ func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordina
}()
}
stage, prog := metadataCatalogingProgress(int64(len(locations)))
prog := metadataCatalogingProgress(int64(len(locations)))
for location := range locations {
stage.Current = location.RealPath
prog.Increment()
prog.AtomicStage.Set(location.Path())
metadata, err := resolver.FileMetadataByLocation(location)
if err != nil {
return nil, err
}
results[location.Coordinates] = metadata
prog.Increment()
}
log.Debugf("file metadata cataloger processed %d files", prog.Current())
prog.AtomicStage.Set(fmt.Sprintf("%s locations", humanize.Comma(prog.Current())))
prog.SetCompleted()
return results, nil
}
func metadataCatalogingProgress(locations int64) (*progress.Stage, *progress.Manual) {
stage := &progress.Stage{}
prog := progress.NewManual(locations)
bus.Publish(partybus.Event{
Type: event.FileMetadataCatalogerStarted,
Value: struct {
progress.Stager
progress.Progressable
}{
Stager: progress.Stager(stage),
Progressable: prog,
func metadataCatalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
info := monitor.GenericTask{
Title: monitor.Title{
Default: "Catalog file metadata",
WhileRunning: "Cataloging file metadata",
OnSuccess: "Cataloged file metadata",
},
})
}
return stage, prog
return bus.StartCatalogerTask(info, locations, "")
}
@@ -168,7 +168,6 @@ func TestFileMetadataCataloger_GivenCoordinates(t *testing.T) {
path string
exists bool
expected file.Metadata
err bool
}{
{
path: "/file-1.txt",
+16 -3
View File
@@ -249,9 +249,22 @@ func extractDescriptor(meta *cyclonedx.Metadata) (desc sbom.Descriptor) {
return
}
for _, t := range *meta.Tools {
desc.Name = t.Name
desc.Version = t.Version
// handle 1.5 component element
if meta.Tools.Components != nil {
for _, t := range *meta.Tools.Components {
desc.Name = t.Name
desc.Version = t.Version
return
}
}
// handle pre-1.5 tool element
if meta.Tools.Tools != nil {
for _, t := range *meta.Tools.Tools {
desc.Name = t.Name
desc.Version = t.Version
return
}
}
return
@@ -114,11 +114,14 @@ func formatCPE(cpeString string) string {
func toBomDescriptor(name, version string, srcMetadata source.Description) *cyclonedx.Metadata {
return &cyclonedx.Metadata{
Timestamp: time.Now().Format(time.RFC3339),
Tools: &[]cyclonedx.Tool{
{
Vendor: "anchore",
Name: name,
Version: version,
Tools: &cyclonedx.ToolsChoice{
Components: &[]cyclonedx.Component{
{
Type: cyclonedx.ComponentTypeApplication,
Author: "anchore",
Name: name,
Version: version,
},
},
},
Properties: toBomProperties(srcMetadata),
@@ -168,13 +168,14 @@ func Test_toBomDescriptor(t *testing.T) {
want: &cyclonedx.Metadata{
Timestamp: "",
Lifecycles: nil,
Tools: &[]cyclonedx.Tool{
{
Vendor: "anchore",
Name: "test-image",
Version: "1.0.0",
Hashes: nil,
ExternalReferences: nil,
Tools: &cyclonedx.ToolsChoice{
Components: &[]cyclonedx.Component{
{
Type: cyclonedx.ComponentTypeApplication,
Author: "anchore",
Name: "test-image",
Version: "1.0.0",
},
},
},
Authors: nil,
@@ -6,13 +6,16 @@
"version": 1,
"metadata": {
"timestamp": "timestamp:redacted",
"tools": [
{
"vendor": "anchore",
"name": "syft",
"version": "v0.42.0-bogus"
}
],
"tools": {
"components": [
{
"type": "application",
"author": "anchore",
"name": "syft",
"version": "v0.42.0-bogus"
}
]
},
"component": {
"bom-ref":"redacted",
"type": "file",
@@ -6,13 +6,16 @@
"version": 1,
"metadata": {
"timestamp": "timestamp:redacted",
"tools": [
{
"vendor": "anchore",
"name": "syft",
"version": "v0.42.0-bogus"
}
],
"tools": {
"components": [
{
"type": "application",
"author": "anchore",
"name": "syft",
"version": "v0.42.0-bogus"
}
]
},
"component": {
"bom-ref":"redacted",
"type": "container",
@@ -3,11 +3,13 @@
<metadata>
<timestamp>redacted</timestamp>
<tools>
<tool>
<vendor>anchore</vendor>
<name>syft</name>
<version>v0.42.0-bogus</version>
</tool>
<components>
<component type="application">
<author>anchore</author>
<name>syft</name>
<version>v0.42.0-bogus</version>
</component>
</components>
</tools>
<component bom-ref="redacted" type="file">
<name>some/path</name>
@@ -3,11 +3,13 @@
<metadata>
<timestamp>redacted</timestamp>
<tools>
<tool>
<vendor>anchore</vendor>
<name>syft</name>
<version>v0.42.0-bogus</version>
</tool>
<components>
<component type="application">
<author>anchore</author>
<name>syft</name>
<version>v0.42.0-bogus</version>
</component>
</components>
</tools>
<component bom-ref="redacted" type="container">
<name>user-image-input</name>
+6 -1
View File
@@ -297,10 +297,15 @@ func TestEncodeFullJSONDocument(t *testing.T) {
},
}
cfg := DefaultEncoderConfig()
cfg.Pretty = true
enc, err := NewFormatEncoderWithConfig(cfg)
require.NoError(t, err)
testutil.AssertEncoderAgainstGoldenSnapshot(t,
testutil.EncoderSnapshotTestConfig{
Subject: s,
Format: NewFormatEncoder(),
Format: enc,
UpdateSnapshot: *updateSnapshot,
PersistRedactionsInSnapshot: true,
IsJSON: true,
@@ -640,6 +640,9 @@ func TestAllLayersResolver_AllLocations(t *testing.T) {
// this isn't important for the test, so we remove them.
paths.Remove("/proc", "/sys", "/dev", "/etc")
// Remove cache created by Mac Rosetta when emulating different arches
paths.Remove("/.cache/rosetta", "/.cache")
pathsList := paths.List()
sort.Strings(pathsList)
@@ -547,6 +547,9 @@ func TestSquashResolver_AllLocations(t *testing.T) {
// this isn't important for the test, so we remove them.
paths.Remove("/proc", "/sys", "/dev", "/etc")
// Remove cache created by Mac Rosetta when emulating different arches
paths.Remove("/.cache/rosetta", "/.cache")
pathsList := paths.List()
sort.Strings(pathsList)
@@ -715,6 +715,18 @@ func Test_Cataloger_DefaultClassifiers_PositiveCases(t *testing.T) {
Metadata: metadata("consul-binary"),
},
},
{
name: "positive-erlang-25.3.2.7",
fixtureDir: "test-fixtures/classifiers/positive/erlang-25.3.2.7",
expected: pkg.Package{
Name: "erlang",
Version: "25.3.2.7",
Type: "binary",
PURL: "pkg:generic/erlang@25.3.2.7",
Locations: locations("erlexec"),
Metadata: metadata("erlang-binary"),
},
},
{
name: "positive-nginx-1.25.1",
fixtureDir: "test-fixtures/classifiers/positive/nginx-1.25.1",
@@ -46,6 +46,15 @@ var defaultClassifiers = []classifier{
PURL: mustPURL("pkg:generic/go@version"),
CPEs: singleCPE("cpe:2.3:a:golang:go:*:*:*:*:*:*:*:*"),
},
{
Class: "julia-binary",
FileGlob: "**/libjulia-internal.so",
EvidenceMatcher: fileContentsVersionMatcher(
`(?m)__init__\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00verify`),
Package: "julia",
PURL: mustPURL("pkg:generic/julia@version"),
CPEs: singleCPE("cpe:2.3:a:julialang:julia:*:*:*:*:*:*:*:*"),
},
{
Class: "helm",
FileGlob: "**/helm",
@@ -172,6 +181,15 @@ var defaultClassifiers = []classifier{
PURL: mustPURL("pkg:generic/php@version"),
CPEs: singleCPE("cpe:2.3:a:php:php:*:*:*:*:*:*:*:*"),
},
{
Class: "php-composer-binary",
FileGlob: "**/composer*",
EvidenceMatcher: fileContentsVersionMatcher(
`(?m)'pretty_version'\s*=>\s*'(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)'`),
Package: "composer",
PURL: mustPURL("pkg:generic/composer@version"),
CPEs: singleCPE("cpe:2.3:a:getcomposer:composer:*:*:*:*:*:*:*:*"),
},
{
Class: "httpd-binary",
FileGlob: "**/httpd",
@@ -265,6 +283,17 @@ var defaultClassifiers = []classifier{
PURL: mustPURL("pkg:generic/ruby@version"),
CPEs: singleCPE("cpe:2.3:a:ruby-lang:ruby:*:*:*:*:*:*:*:*"),
},
{
Class: "erlang-binary",
FileGlob: "**/erlexec",
EvidenceMatcher: fileContentsVersionMatcher(
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
`(?m)\<artificial\>\x00/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+?)/erts/`,
),
Package: "erlang",
PURL: mustPURL("pkg:generic/erlang@version"),
CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"),
},
{
Class: "consul-binary",
FileGlob: "**/consul",
+29 -30
View File
@@ -6,14 +6,14 @@ import (
"runtime/debug"
"sync"
"github.com/dustin/go-humanize"
"github.com/hashicorp/go-multierror"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/monitor"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
@@ -35,21 +35,6 @@ type catalogResult struct {
Error error
}
// newMonitor creates a new Monitor object and publishes the object on the bus as a PackageCatalogerStarted event.
func newMonitor() (*progress.Manual, *progress.Manual) {
filesProcessed := progress.Manual{}
packagesDiscovered := progress.Manual{}
bus.Publish(partybus.Event{
Type: event.PackageCatalogerStarted,
Value: Monitor{
FilesProcessed: progress.Monitorable(&filesProcessed),
PackagesDiscovered: progress.Monitorable(&packagesDiscovered),
},
})
return &filesProcessed, &packagesDiscovered
}
func runCataloger(cataloger pkg.Cataloger, resolver file.Resolver) (catalogerResult *catalogResult, err error) {
// handle individual cataloger panics
defer func() {
@@ -101,6 +86,7 @@ func runCataloger(cataloger pkg.Cataloger, resolver file.Resolver) (catalogerRes
}
catalogerResult.Packages = append(catalogerResult.Packages, p)
}
catalogerResult.Relationships = append(catalogerResult.Relationships, relationships...)
log.WithFields("cataloger", cataloger.Name()).Trace("cataloging complete")
return catalogerResult, err
@@ -116,9 +102,7 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
catalog := pkg.NewCollection()
var allRelationships []artifact.Relationship
filesProcessed, packagesDiscovered := newMonitor()
defer filesProcessed.SetCompleted()
defer packagesDiscovered.SetCompleted()
prog := monitorPackageCatalogingTask()
// perform analysis, accumulating errors for each failed analysis
var errs error
@@ -131,10 +115,11 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
jobs := make(chan pkg.Cataloger, nCatalogers)
results := make(chan *catalogResult, nCatalogers)
discoveredPackages := make(chan int64, nCatalogers)
waitGroup := sync.WaitGroup{}
var totalPackagesDiscovered int64
for i := 0; i < parallelism; i++ {
waitGroup.Add(1)
@@ -148,20 +133,16 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
// ensure we set the error to be aggregated
result.Error = err
discoveredPackages <- result.Discovered
prog.Add(result.Discovered)
totalPackagesDiscovered += result.Discovered
count := humanize.Comma(totalPackagesDiscovered)
prog.AtomicStage.Set(fmt.Sprintf("%s packages", count))
results <- result
}
}()
}
// dynamically show updated discovered package status
go func() {
for discovered := range discoveredPackages {
packagesDiscovered.Add(discovered)
}
}()
// Enqueue the jobs
for _, cataloger := range catalogers {
jobs <- cataloger
@@ -171,7 +152,6 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
// Wait for the jobs to finish
waitGroup.Wait()
close(results)
close(discoveredPackages)
// collect the results
for result := range results {
@@ -186,6 +166,12 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
allRelationships = append(allRelationships, pkg.NewRelationships(catalog)...)
if errs != nil {
prog.SetError(errs)
} else {
prog.SetCompleted()
}
return catalog, allRelationships, errs
}
@@ -228,3 +214,16 @@ func packageFileOwnershipRelationships(p pkg.Package, resolver file.PathResolver
}
return relationships, nil
}
func monitorPackageCatalogingTask() *monitor.CatalogerTaskProgress {
info := monitor.GenericTask{
Title: monitor.Title{
Default: "Catalog packages",
WhileRunning: "Cataloging packages",
OnSuccess: "Cataloged packages",
},
HideOnSuccess: false,
}
return bus.StartCatalogerTask(info, -1, "")
}
+4 -4
View File
@@ -83,9 +83,9 @@ func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
haskell.NewHackageCataloger(),
java.NewArchiveCataloger(cfg.JavaConfig()),
java.NewGradleLockfileCataloger(),
java.NewPomCataloger(),
java.NewPomCataloger(cfg.JavaConfig()),
java.NewNativeImageCataloger(),
javascript.NewLockCataloger(),
javascript.NewLockCataloger(cfg.Javascript),
nix.NewStoreCataloger(),
php.NewComposerLockCataloger(),
gentoo.NewPortageCataloger(),
@@ -122,9 +122,9 @@ func AllCatalogers(cfg Config) []pkg.Cataloger {
haskell.NewHackageCataloger(),
java.NewArchiveCataloger(cfg.JavaConfig()),
java.NewGradleLockfileCataloger(),
java.NewPomCataloger(),
java.NewPomCataloger(cfg.JavaConfig()),
java.NewNativeImageCataloger(),
javascript.NewLockCataloger(),
javascript.NewLockCataloger(cfg.Javascript),
javascript.NewPackageCataloger(),
kernel.NewLinuxKernelCataloger(cfg.LinuxKernel),
nix.NewStoreCataloger(),
@@ -115,6 +115,7 @@
"google-kubernetes-engine": "cpe:2.3:a:jenkins:google_kubernetes_engine:*:*:*:*:*:jenkins:*:*",
"google-oauth": "cpe:2.3:a:jenkins:google_oauth_credentials:*:*:*:*:*:jenkins:*:*",
"google-play-android-publisher": "cpe:2.3:a:jenkins:google-play-android-publisher:*:*:*:*:*:jenkins:*:*",
"gradle": "cpe:2.3:a:jenkins:gradle:*:*:*:*:*:jenkins:*:*",
"groovy": "cpe:2.3:a:jenkins:groovy:*:*:*:*:*:jenkins:*:*",
"harvest": "cpe:2.3:a:jenkins:harvest_scm:*:*:*:*:*:jenkins:*:*",
"hipchat": "cpe:2.3:a:atlassian:hipchat:*:*:*:*:*:jenkins:*:*",
@@ -288,6 +289,7 @@
"@awsui/components-react": "cpe:2.3:a:amazon:awsui\\/components-react:*:*:*:*:*:node.js:*:*",
"@azure/ms-rest-nodeauth": "cpe:2.3:a:microsoft:ms-rest-nodeauth:*:*:*:*:*:node.js:*:*",
"@backstage/plugin-auth-backend": "cpe:2.3:a:linuxfoundation:auth_backend:*:*:*:*:*:node.js:*:*",
"@evershop/evershop": "cpe:2.3:a:evershop:evershop:*:*:*:*:*:node.js:*:*",
"@fastly/js-compute": "cpe:2.3:a:fastly:js-compute:*:*:*:*:*:node.js:*:*",
"@firebase/util": "cpe:2.3:a:google:firebase\\/util:*:*:*:*:*:node.js:*:*",
"@github/paste-markdown": "cpe:2.3:a:paste-markdown_project:paste-markdown:*:*:*:*:*:node.js:*:*",
@@ -295,9 +297,11 @@
"@nuxt/devalue": "cpe:2.3:a:nuxtjs:\\@nuxt\\/devalue:*:*:*:*:*:node.js:*:*",
"@progfay/scrapbox-parser": "cpe:2.3:a:scrapbox-parser_project:scrapbox-parser:*:*:*:*:*:node.js:*:*",
"@rkesters/gnuplot": "cpe:2.3:a:gnuplot_project:gnuplot:*:*:*:*:*:node.js:*:*",
"@sap/xssec": "cpe:2.3:a:sap:\\@sap\\/xssec:*:*:*:*:*:node.js:*:*",
"@solana/pay": "cpe:2.3:a:solanalabs:pay:*:*:*:*:*:*:*:*",
"@strikeentco/set": "cpe:2.3:a:set_project:set:*:*:*:*:*:node.js:*:*",
"@thi.ng/egf": "cpe:2.3:a:\\@thi.ng\\/egf_project:\\@thi.ng\\/egf:*:*:*:*:*:node.js:*:*",
"@vue/devtools": "cpe:2.3:a:vuejs:devtools:*:*:*:*:*:node.js:*:*",
"@zxcvbn-ts/core": "cpe:2.3:a:zxcvbn-ts_project:zxcvbn-ts:*:*:*:*:*:node.js:*:*",
"Proto": "cpe:2.3:a:proto_project:proto:*:*:*:*:*:node.js:*:*",
"Templ8": "cpe:2.3:a:templ8_project:templ8:*:*:*:*:*:node.js:*:*",
@@ -389,6 +393,7 @@
"conf-cfg-ini": "cpe:2.3:a:conf-cfg-ini_project:conf-cfg-ini:*:*:*:*:*:node.js:*:*",
"confinit": "cpe:2.3:a:confinit_project:confinit:*:*:*:*:*:node.js:*:*",
"confucious": "cpe:2.3:a:realseriousgames:confucious:*:*:*:*:*:node.js:*:*",
"connect-multiparty": "cpe:2.3:a:connect-multiparty_project:connect-multiparty:*:*:*:*:*:*:*:*",
"connect-pg-simple": "cpe:2.3:a:connect-pg-simple_project:connect-pg-simple:*:*:*:*:*:node.js:*:*",
"connection-tester": "cpe:2.3:a:connection-tester_project:connection-tester:*:*:*:*:*:node.js:*:*",
"console-io": "cpe:2.3:a:console-io_project:console-io:*:*:*:*:*:node.js:*:*",
@@ -1084,11 +1089,15 @@
"reqmgr2": "cpe:2.3:a:reqmgr2_project:reqmgr2:*:*:*:*:*:python:*:*",
"reqmon": "cpe:2.3:a:reqmon_project:reqmon:*:*:*:*:*:python:*:*",
"requests-xml": "cpe:2.3:a:requests-xml_project:requests-xml:*:*:*:*:*:python:*:*",
"rondolu-yt-concate": "cpe:2.3:a:rondolu-yt-concate_project:rondolu-yt-concate:*:*:*:*:*:pypi:*:*",
"rope": "cpe:2.3:a:rope_project:rope:*:*:*:*:*:python:*:*",
"rply": "cpe:2.3:a:rply_project:rply:*:*:*:*:*:*:*:*",
"rsa": "cpe:2.3:a:python:rsa:*:*:*:*:*:python:*:*",
"ruamel.yaml": "cpe:2.3:a:ruamel.yaml_project:ruamel.yaml:*:*:*:*:*:*:*:*",
"sap-xssec": "cpe:2.3:a:sap:sap-xssec:*:*:*:*:*:python:*:*",
"scoptrial": "cpe:2.3:a:scoptrial_project:scoptrial:*:*:*:*:*:pypi:*:*",
"simiki": "cpe:2.3:a:simiki_project:simiki:*:*:*:*:*:*:*:*",
"sixfab-power-python-api": "cpe:2.3:a:sixfab-tool_project:sixfab-tool:*:*:*:*:*:pypi:*:*",
"slashify": "cpe:2.3:a:google:slashify:*:*:*:*:*:node.js:*:*",
"sopel-plugins.channelmgnt": "cpe:2.3:a:mirahezebots:channelmgnt:*:*:*:*:*:sopel:*:*",
"spacy": "cpe:2.3:a:explosion:spacy:*:*:*:*:*:python:*:*",
@@ -1219,6 +1228,7 @@
"bzip2": "cpe:2.3:a:bzip2_project:bzip2:*:*:*:*:*:rust:*:*",
"cache": "cpe:2.3:a:cache_project:cache:*:*:*:*:*:rust:*:*",
"cached": "cpe:2.3:a:cached_project:cached:*:*:*:*:*:rust:*:*",
"candid": "cpe:2.3:a:dfinity:candid:*:*:*:*:*:rust:*:*",
"cbox": "cpe:2.3:a:cbox_project:cbox:*:*:*:*:*:rust:*:*",
"ckb": "cpe:2.3:a:nervos:ckb:*:*:*:*:*:rust:*:*",
"conduit-hyper": "cpe:2.3:a:conduit-hyper_project:conduit-hyper:*:*:*:*:*:rust:*:*",
+1 -1
View File
@@ -294,7 +294,7 @@ func GetManifestFieldGroupIDs(manifest *pkg.JavaManifest, fields []string) (grou
}
func cleanGroupID(groupID string) string {
return strings.TrimSpace(removeOSCIDirectives(groupID))
return strings.TrimSpace(strings.Split(removeOSCIDirectives(groupID), "#")[0])
}
func removeOSCIDirectives(groupID string) string {
File diff suppressed because it is too large Load Diff
@@ -161,6 +161,17 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
},
expects: []string{"io.jenkins-ci.plugin.thing"},
},
{
name: "clean # suffixes",
pkg: pkg.Package{
Metadata: pkg.JavaArchive{
PomProperties: &pkg.JavaPomProperties{
GroupID: "org.elasticsearch.plugin#parent-join;6.8.15",
},
},
},
expects: []string{"org.elasticsearch.plugin"},
},
{
name: "from artifactID",
pkg: pkg.Package{
+3
View File
@@ -4,6 +4,7 @@ import (
"github.com/anchore/syft/syft/cataloging"
"github.com/anchore/syft/syft/pkg/cataloger/golang"
"github.com/anchore/syft/syft/pkg/cataloger/java"
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
"github.com/anchore/syft/syft/pkg/cataloger/python"
)
@@ -15,6 +16,7 @@ type Config struct {
LinuxKernel kernel.LinuxKernelCatalogerConfig
Python python.CatalogerConfig
Java java.ArchiveCatalogerConfig
Javascript javascript.CatalogerConfig
Catalogers []string
Parallelism int
ExcludeBinaryOverlapByOwnership bool
@@ -27,6 +29,7 @@ func DefaultConfig() Config {
LinuxKernel: kernel.DefaultLinuxCatalogerConfig(),
Python: python.DefaultCatalogerConfig(),
Java: java.DefaultArchiveCatalogerConfig(),
Javascript: javascript.DefaultCatalogerConfig(),
ExcludeBinaryOverlapByOwnership: true,
}
}
@@ -58,23 +58,14 @@ func parseDotnetPortableExecutable(_ file.Resolver, _ *generic.Environment, f fi
func buildDotNetPackage(versionResources map[string]string, f file.LocationReadCloser) (dnpkg pkg.Package, err error) {
name := findName(versionResources)
if name == "" {
return dnpkg, fmt.Errorf("unable to find FileDescription, or ProductName in PE file: %s", f.RealPath)
return dnpkg, fmt.Errorf("unable to find PE name in file: %s", f.RealPath)
}
version := findVersion(versionResources)
if strings.TrimSpace(version) == "" {
return dnpkg, fmt.Errorf("unable to find FileVersion in PE file: %s", f.RealPath)
if version == "" {
return dnpkg, fmt.Errorf("unable to find PE version in file: %s", f.RealPath)
}
purl := packageurl.NewPackageURL(
packageurl.TypeNuget, // See explanation in syft/pkg/cataloger/dotnet/package.go as to why this was chosen.
"",
name,
version,
nil,
"",
).ToString()
metadata := pkg.DotnetPortableExecutableEntry{
AssemblyVersion: versionResources["Assembly Version"],
LegalCopyright: versionResources["LegalCopyright"],
@@ -91,7 +82,7 @@ func buildDotNetPackage(versionResources map[string]string, f file.LocationReadC
Locations: file.NewLocationSet(f.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
Type: pkg.DotnetPkg,
Language: pkg.Dotnet,
PURL: purl,
PURL: portableExecutablePackageURL(name, version),
Metadata: metadata,
}
@@ -100,30 +91,128 @@ func buildDotNetPackage(versionResources map[string]string, f file.LocationReadC
return dnpkg, nil
}
func findVersion(versionResources map[string]string) string {
for _, key := range []string{"FileVersion"} {
if version, ok := versionResources[key]; ok {
if strings.TrimSpace(version) == "" {
continue
}
fields := strings.Fields(version)
if len(fields) > 0 {
return fields[0]
}
func portableExecutablePackageURL(name, version string) string {
return packageurl.NewPackageURL(
packageurl.TypeNuget, // See explanation in syft/pkg/cataloger/dotnet/package.go as to why this was chosen.
"",
name,
version,
nil,
"",
).ToString()
}
func extractVersion(version string) string {
version = strings.TrimSpace(version)
out := ""
// some example versions are: "1, 0, 0, 0", "Release 73" or "4.7.4076.0 built by: NET472REL1LAST_B"
// so try to split it and take the first parts that look numeric
for i, f := range strings.Fields(version) {
// if the output already has a number but the current segment does not have a number,
// return what we found for the version
if containsNumber(out) && !containsNumber(f) {
return out
}
if i == 0 {
out = f
} else {
out += " " + f
}
}
return out
}
func findVersion(versionResources map[string]string) string {
productVersion := extractVersion(versionResources["ProductVersion"])
fileVersion := extractVersion(versionResources["FileVersion"])
if productVersion == "" {
return fileVersion
}
productVersionDetail := punctuationCount(productVersion)
fileVersionDetail := punctuationCount(fileVersion)
if containsNumber(productVersion) && productVersionDetail >= fileVersionDetail {
return productVersion
}
if containsNumber(fileVersion) && fileVersionDetail > 0 {
return fileVersion
}
if containsNumber(productVersion) {
return productVersion
}
if containsNumber(fileVersion) {
return fileVersion
}
return productVersion
}
func containsNumber(s string) bool {
return numberRegex.MatchString(s)
}
func punctuationCount(s string) int {
return len(versionPunctuationRegex.FindAllString(s, -1))
}
var (
// spaceRegex includes nbsp (#160) considered to be a space character
spaceRegex = regexp.MustCompile(`[\s\xa0]+`)
numberRegex = regexp.MustCompile(`\d`)
versionPunctuationRegex = regexp.MustCompile(`[.,]+`)
)
func findName(versionResources map[string]string) string {
// PE files found in the wild _not_ authored by Microsoft seem to use ProductName as a clear
// identifier of the software
nameFields := []string{"ProductName", "FileDescription", "InternalName", "OriginalFilename"}
if isMicrosoft(versionResources) {
// Microsoft seems to be consistent using the FileDescription, with a few that are blank and have
// fallbacks to ProductName last, as this is often something very broad like "Microsoft Windows"
nameFields = []string{"FileDescription", "InternalName", "OriginalFilename", "ProductName"}
}
for _, field := range nameFields {
value := spaceNormalize(versionResources[field])
if value == "" {
continue
}
return value
}
return ""
}
func findName(versionResources map[string]string) string {
for _, key := range []string{"FileDescription", "ProductName"} {
if name, ok := versionResources[key]; ok {
if strings.TrimSpace(name) == "" {
continue
}
trimmed := strings.TrimSpace(name)
return regexp.MustCompile(`[^a-zA-Z0-9.]+`).ReplaceAllString(trimmed, "")
}
// normalizes a string to a trimmed version with all contigous whitespace collapsed to a single space character
func spaceNormalize(value string) string {
value = strings.TrimSpace(value)
if value == "" {
return ""
}
return ""
// ensure valid utf8 text
value = strings.ToValidUTF8(value, "")
// consolidate all space characters
value = spaceRegex.ReplaceAllString(value, " ")
// remove other non-space, non-printable characters
value = regexp.MustCompile(`[\x00-\x1f]`).ReplaceAllString(value, "")
// consolidate all space characters again in case other non-printables were in-between
value = spaceRegex.ReplaceAllString(value, " ")
// finally, remove any remaining surrounding whitespace
value = strings.TrimSpace(value)
return value
}
func isMicrosoft(versionResources map[string]string) bool {
return strings.Contains(strings.ToLower(versionResources["CompanyName"]), "microsoft") ||
strings.Contains(strings.ToLower(versionResources["ProductName"]), "microsoft")
}
@@ -32,12 +32,8 @@ func TestParseDotnetPortableExecutable(t *testing.T) {
"Assembly Version": "3.14.2.11",
},
expectedPackage: pkg.Package{
Name: "ActiveDirectoryAuthenticationLibrary",
Version: "3.14.40721.0918",
Locations: file.NewLocationSet(file.NewLocation("").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
Type: pkg.DotnetPkg,
Language: pkg.Dotnet,
PURL: "pkg:nuget/ActiveDirectoryAuthenticationLibrary@3.14.40721.0918",
Name: "Active Directory Authentication Library",
Version: "3.14.40721.0918",
Metadata: pkg.DotnetPortableExecutableEntry{
AssemblyVersion: "3.14.2.11",
LegalCopyright: "Copyright (c) Microsoft Corporation. All rights reserved.",
@@ -52,7 +48,7 @@ func TestParseDotnetPortableExecutable(t *testing.T) {
name: "dotnet package with malformed field and extended version",
versionResources: map[string]string{
"CompanyName": "Microsoft Corporation",
"FileDescription": "äbFileVersion",
"FileDescription": "äbFile\xa0\xa1Versi on",
"FileVersion": "4.6.25512.01 built by: dlab-DDVSOWINAGE016. Commit Hash: d0d5c7b49271cadb6d97de26d8e623e98abdc8db",
"InternalName": "äbFileVersion",
"LegalCopyright": "© Microsoft Corporation. All rights reserved.",
@@ -61,13 +57,9 @@ func TestParseDotnetPortableExecutable(t *testing.T) {
"ProductVersion": "4.6.25512.01 built by: dlab-DDVSOWINAGE016. Commit Hash: d0d5c7b49271cadb6d97de26d8e623e98abdc8db",
},
expectedPackage: pkg.Package{
Name: "bFileVersion",
Name: "äbFileVersi on",
Version: "4.6.25512.01",
Locations: file.NewLocationSet(
file.NewLocation("").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
Type: pkg.DotnetPkg,
Language: pkg.Dotnet,
PURL: "pkg:nuget/bFileVersion@4.6.25512.01",
PURL: "pkg:nuget/%C3%A4bFileVersi%20on@4.6.25512.01",
Metadata: pkg.DotnetPortableExecutableEntry{
LegalCopyright: "© Microsoft Corporation. All rights reserved.",
InternalName: "äb\x01FileVersion",
@@ -77,16 +69,208 @@ func TestParseDotnetPortableExecutable(t *testing.T) {
},
},
},
{
name: "System.Data.Linq.dll",
versionResources: map[string]string{
"CompanyName": "Microsoft Corporation",
"FileDescription": "System.Data.Linq.dll",
"FileVersion": "4.7.3190.0 built by: NET472REL1LAST_C",
"InternalName": "System.Data.Linq.dll",
"LegalCopyright": "© Microsoft Corporation. All rights reserved.",
"OriginalFilename": "System.Data.Linq.dll",
"ProductName": "Microsoft® .NET Framework",
"ProductVersion": "4.7.3190.0",
},
expectedPackage: pkg.Package{
Name: "System.Data.Linq.dll",
Version: "4.7.3190.0",
},
},
{
name: "curl",
versionResources: map[string]string{
"CompanyName": "curl, https://curl.se/",
"FileDescription": "The curl executable",
"FileVersion": "8.4.0",
"InternalName": "curl",
"LegalCopyright": "© Daniel Stenberg, <daniel@haxx.se>.",
"OriginalFilename": "curl.exe",
"ProductName": "The curl executable",
"ProductVersion": "8.4.0",
},
expectedPackage: pkg.Package{
Name: "The curl executable",
Version: "8.4.0",
},
},
{
name: "Prometheus",
versionResources: map[string]string{
"AssemblyVersion": "8.0.0.0",
"CompanyName": "",
"FileDescription": "",
"FileVersion": "8.0.1",
"InternalName": "Prometheus.AspNetCore.dll",
"OriginalFilename": "Prometheus.AspNetCore.dll",
"ProductName": "",
"ProductVersion": "8.0.1",
},
expectedPackage: pkg.Package{
Name: "Prometheus.AspNetCore.dll",
Version: "8.0.1",
},
},
{
name: "Hidden Input",
versionResources: map[string]string{
"FileDescription": "Reads from stdin without leaking info to the terminal and outputs back to stdout",
"FileVersion": "1, 0, 0, 0",
"InternalName": "hiddeninput",
"LegalCopyright": "Jordi Boggiano - 2012",
"OriginalFilename": "hiddeninput.exe",
"ProductName": "Hidden Input",
"ProductVersion": "1, 0, 0, 0",
},
expectedPackage: pkg.Package{
Name: "Hidden Input",
Version: "1, 0, 0, 0",
},
},
{
name: "SQLite3",
versionResources: map[string]string{
"CompanyName": "SQLite Development Team",
"FileDescription": "SQLite is a software library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine.",
"FileVersion": "3.23.2",
"InternalName": "sqlite3",
"LegalCopyright": "http://www.sqlite.org/copyright.html",
"ProductName": "SQLite",
"ProductVersion": "3.23.2",
},
expectedPackage: pkg.Package{
Name: "SQLite",
Version: "3.23.2",
},
},
{
name: "Brave Browser",
versionResources: map[string]string{
"CompanyName": "Brave Software, Inc.",
"FileDescription": "Brave Browser",
"FileVersion": "80.1.7.92",
"InternalName": "chrome_exe",
"LegalCopyright": "Copyright 2016 The Brave Authors. All rights reserved.",
"OriginalFilename": "chrome.exe",
"ProductName": "Brave Browser",
"ProductVersion": "80.1.7.92",
},
expectedPackage: pkg.Package{
Name: "Brave Browser",
Version: "80.1.7.92",
},
},
{
name: "Better product version",
versionResources: map[string]string{
"FileDescription": "Better version",
"FileVersion": "80.1.7",
"ProductVersion": "80.1.7.92",
},
expectedPackage: pkg.Package{
Name: "Better version",
Version: "80.1.7.92",
},
},
{
name: "Better file version",
versionResources: map[string]string{
"FileDescription": "Better version",
"FileVersion": "80.1.7.92",
"ProductVersion": "80.1.7",
},
expectedPackage: pkg.Package{
Name: "Better version",
Version: "80.1.7.92",
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
location := file.NewLocation("")
f := file.LocationReadCloser{
Location: file.NewLocation(""),
Location: location,
}
got, err := buildDotNetPackage(tc.versionResources, f)
assert.NoErrorf(t, err, "failed to build package from version resources: %+v", tc.versionResources)
// ignore certain metadata
if tc.expectedPackage.Metadata == nil {
got.Metadata = nil
}
// set known defaults
if tc.expectedPackage.Type == "" {
tc.expectedPackage.Type = pkg.DotnetPkg
}
if tc.expectedPackage.Language == "" {
tc.expectedPackage.Language = pkg.Dotnet
}
if tc.expectedPackage.PURL == "" {
tc.expectedPackage.PURL = portableExecutablePackageURL(tc.expectedPackage.Name, tc.expectedPackage.Version)
}
tc.expectedPackage.Locations = file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
pkgtest.AssertPackagesEqual(t, tc.expectedPackage, got)
})
}
}
func Test_extractVersion(t *testing.T) {
tests := []struct {
input string
expected string
}{
{
input: "1, 0, 0, 0",
expected: "1, 0, 0, 0",
},
{
input: "Release 73",
expected: "Release 73",
},
{
input: "4.7.4076.0 built by: NET472REL1LAST_B",
expected: "4.7.4076.0",
},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
got := extractVersion(test.input)
assert.Equal(t, test.expected, got)
})
}
}
func Test_spaceNormalize(t *testing.T) {
tests := []struct {
input string
expected string
}{
{
expected: "some spaces apart",
input: " some spaces\n\t\t \n\rapart\n",
},
{
expected: "söme ¡nvalid characters",
input: "\rsöme \u0001¡nvalid\t characters\n",
},
}
for _, test := range tests {
t.Run(test.expected, func(t *testing.T) {
got := spaceNormalize(test.input)
assert.Equal(t, test.expected, got)
})
}
}
+18 -14
View File
@@ -20,6 +20,7 @@ import (
"github.com/go-git/go-git/v5/storage/memory"
"github.com/scylladb/go-set/strset"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/licenses"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/event/monitor"
@@ -31,7 +32,6 @@ import (
type goLicenses struct {
opts CatalogerConfig
localModCacheResolver file.WritableResolver
progress *monitor.CatalogerTask
lowerLicenseFileNames *strset.Set
}
@@ -39,11 +39,6 @@ func newGoLicenses(opts CatalogerConfig) goLicenses {
return goLicenses{
opts: opts,
localModCacheResolver: modCacheResolver(opts.LocalModCacheDir),
progress: &monitor.CatalogerTask{
SubStatus: true,
RemoveOnCompletion: true,
Title: "Downloading go mod",
},
lowerLicenseFileNames: strset.New(lowercaseLicenseFiles()...),
}
}
@@ -123,7 +118,16 @@ func (c *goLicenses) getLicensesFromRemote(moduleName, moduleVersion string) ([]
proxies := remotesForModule(c.opts.Proxies, c.opts.NoProxy, moduleName)
fsys, err := getModule(c.progress, proxies, moduleName, moduleVersion)
prog := bus.StartCatalogerTask(monitor.GenericTask{
Title: monitor.Title{
Default: "Download go mod",
WhileRunning: "Downloading go mod",
OnSuccess: "Downloaded go mod",
},
HideOnSuccess: true,
}, -1, "")
fsys, err := getModule(prog, proxies, moduleName, moduleVersion)
if err != nil {
return nil, err
}
@@ -206,7 +210,7 @@ func processCaps(s string) string {
})
}
func getModule(progress *monitor.CatalogerTask, proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
func getModule(progress *monitor.CatalogerTaskProgress, proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
for _, proxy := range proxies {
u, _ := url.Parse(proxy)
if proxy == "direct" {
@@ -218,7 +222,7 @@ func getModule(progress *monitor.CatalogerTask, proxies []string, moduleName, mo
fsys, err = getModuleProxy(progress, proxy, moduleName, moduleVersion)
case "file":
p := filepath.Join(u.Path, moduleName, "@v", moduleVersion)
progress.SetValue(fmt.Sprintf("file: %s", p))
progress.AtomicStage.Set(fmt.Sprintf("file: %s", p))
fsys = os.DirFS(p)
}
if fsys != nil {
@@ -228,9 +232,9 @@ func getModule(progress *monitor.CatalogerTask, proxies []string, moduleName, mo
return
}
func getModuleProxy(progress *monitor.CatalogerTask, proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
func getModuleProxy(progress *monitor.CatalogerTaskProgress, proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
u := fmt.Sprintf("%s/%s/@v/%s.zip", proxy, moduleName, moduleVersion)
progress.SetValue(u)
progress.AtomicStage.Set(u)
// get the module zip
resp, err := http.Get(u) //nolint:gosec
@@ -241,7 +245,7 @@ func getModuleProxy(progress *monitor.CatalogerTask, proxy string, moduleName st
if resp.StatusCode != http.StatusOK {
u = fmt.Sprintf("%s/%s/@v/%s.zip", proxy, strings.ToLower(moduleName), moduleVersion)
progress.SetValue(u)
progress.AtomicStage.Set(u)
// try lowercasing it; some packages have mixed casing that really messes up the proxy
resp, err = http.Get(u) //nolint:gosec
@@ -284,14 +288,14 @@ func findVersionPath(f fs.FS, dir string) string {
return ""
}
func getModuleRepository(progress *monitor.CatalogerTask, moduleName string, moduleVersion string) (fs.FS, error) {
func getModuleRepository(progress *monitor.CatalogerTaskProgress, moduleName string, moduleVersion string) (fs.FS, error) {
repoName := moduleName
parts := strings.Split(moduleName, "/")
if len(parts) > 2 {
repoName = fmt.Sprintf("%s/%s/%s", parts[0], parts[1], parts[2])
}
progress.SetValue(fmt.Sprintf("git: %s", repoName))
progress.AtomicStage.Set(fmt.Sprintf("git: %s", repoName))
f := memfs.New()
buf := &bytes.Buffer{}
+12 -2
View File
@@ -63,6 +63,9 @@ func parseStackLock(_ file.Resolver, _ *generic.Environment, reader file.Locatio
}
for _, pack := range lockFile.Packages {
if pack.Completed.Hackage == "" {
continue
}
pkgName, pkgVersion, pkgHash := parseStackPackageEncoding(pack.Completed.Hackage)
pkgs = append(
pkgs,
@@ -80,13 +83,20 @@ func parseStackLock(_ file.Resolver, _ *generic.Environment, reader file.Locatio
return pkgs, nil, nil
}
func parseStackPackageEncoding(pkgEncoding string) (name, version, hash string) {
lastDashIdx := strings.LastIndex(pkgEncoding, "-")
if lastDashIdx == -1 {
name = pkgEncoding
return
}
name = pkgEncoding[:lastDashIdx]
remainingEncoding := pkgEncoding[lastDashIdx+1:]
encodingSplits := strings.Split(remainingEncoding, "@")
version = encodingSplits[0]
startHash, endHash := strings.Index(encodingSplits[1], ":")+1, strings.Index(encodingSplits[1], ",")
hash = encodingSplits[1][startHash:endHash]
if len(encodingSplits) > 1 {
startHash, endHash := strings.Index(encodingSplits[1], ":")+1, strings.Index(encodingSplits[1], ",")
hash = encodingSplits[1][startHash:endHash]
}
return
}
@@ -67,6 +67,19 @@ packages:
sha256: 557c438345de19f82bf01d676100da2a191ef06f624e7a4b90b09ac17cbb52a5
original:
hackage: ptr-0.16.8.2@sha256:708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac,3959
- completed:
commit: a5847301404583e16d55cd4d051b8e605d704fbc
git: https://github.com/runtimeverification/haskell-backend.git
name: kore
pantry-tree:
sha256: 30a502eda589be5af735b1b59760ce3e0235c0cae8961978a46b3564dd8db32b
size: 44685
subdir: kore
version: 0.60.0.0
original:
commit: a5847301404583e16d55cd4d051b8e605d704fbc
git: https://github.com/runtimeverification/haskell-backend.git
subdir: kore
snapshots:
- completed:
size: 618951
+30 -114
View File
@@ -3,15 +3,9 @@ package java
import (
"crypto"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path"
"strings"
"time"
"github.com/vifraa/gopom"
intFile "github.com/anchore/syft/internal/file"
"github.com/anchore/syft/internal/licenses"
@@ -263,19 +257,13 @@ func findLicenseFromJavaMetadata(name string, manifest *pkg.JavaManifest, versio
if gID := groupIDFromJavaMetadata(name, pkg.JavaArchive{Manifest: manifest}); gID != "" {
groupID = gID
}
pomLicenses, err := recursivelyFindLicensesFromParentPom(groupID, name, version, j.cfg)
if err != nil {
log.Tracef("unable to get parent pom from Maven central: %v", err)
}
pomLicenses := recursivelyFindLicensesFromParentPom(groupID, name, version, j.cfg)
if len(pomLicenses) == 0 {
// Try removing the last part of the groupId, as sometimes it duplicates the artifactId
packages := strings.Split(groupID, ".")
groupID = strings.Join(packages[:len(packages)-1], ".")
pomLicenses, err = recursivelyFindLicensesFromParentPom(groupID, name, version, j.cfg)
if err != nil {
log.Tracef("unable to get parent pom from Maven central: %v", err)
}
pomLicenses = recursivelyFindLicensesFromParentPom(groupID, name, version, j.cfg)
}
if len(pomLicenses) > 0 {
@@ -320,8 +308,18 @@ func (j *archiveParser) guessMainPackageNameAndVersionFromPomInfo() (name, versi
if version == "" && pomProjectObject != nil {
version = pomProjectObject.Version
}
if pomProjectObject != nil && j.cfg.UseNetwork {
findPomLicenses(pomProjectObject, j.cfg)
if j.cfg.UseNetwork {
if pomProjectObject == nil {
// If we have no pom.xml, check maven central using pom.properties
parentLicenses := recursivelyFindLicensesFromParentPom(pomPropertiesObject.GroupID, pomPropertiesObject.ArtifactID, pomPropertiesObject.Version, j.cfg)
if len(parentLicenses) > 0 {
for _, licenseName := range parentLicenses {
licenses = append(licenses, pkg.NewLicenseFromFields(licenseName, "", nil))
}
}
} else {
findPomLicenses(pomProjectObject, j.cfg)
}
}
if pomProjectObject != nil {
@@ -341,16 +339,12 @@ func artifactIDMatchesFilename(artifactID, fileName string) bool {
func findPomLicenses(pomProjectObject *parsedPomProject, cfg ArchiveCatalogerConfig) {
// If we don't have any licenses until now, and if we have a parent Pom, then we'll check the parent pom in maven central for licenses.
if pomProjectObject != nil && pomProjectObject.Parent != nil && len(pomProjectObject.Licenses) == 0 {
parentLicenses, err := recursivelyFindLicensesFromParentPom(
parentLicenses := recursivelyFindLicensesFromParentPom(
pomProjectObject.Parent.GroupID,
pomProjectObject.Parent.ArtifactID,
pomProjectObject.Parent.Version,
cfg)
if err != nil {
// We don't want to abort here as the parent pom might not exist in Maven Central, we'll just log the error
log.Tracef("unable to get parent pom from Maven central: %v", err)
return
}
if len(parentLicenses) > 0 {
for _, licenseName := range parentLicenses {
pomProjectObject.Licenses = append(pomProjectObject.Licenses, pkg.NewLicenseFromFields(licenseName, "", nil))
@@ -359,96 +353,6 @@ func findPomLicenses(pomProjectObject *parsedPomProject, cfg ArchiveCatalogerCon
}
}
func formatMavenPomURL(groupID, artifactID, version, mavenBaseURL string) (requestURL string, err error) {
// groupID needs to go from maven.org -> maven/org
urlPath := strings.Split(groupID, ".")
artifactPom := fmt.Sprintf("%s-%s.pom", artifactID, version)
urlPath = append(urlPath, artifactID, version, artifactPom)
// ex:"https://repo1.maven.org/maven2/groupID/artifactID/artifactPom
requestURL, err = url.JoinPath(mavenBaseURL, urlPath...)
if err != nil {
return requestURL, fmt.Errorf("could not construct maven url: %w", err)
}
return requestURL, err
}
func recursivelyFindLicensesFromParentPom(groupID, artifactID, version string, cfg ArchiveCatalogerConfig) ([]string, error) {
var licenses []string
// As there can be nested parent poms, we'll recursively check for licenses until we reach the max depth
for i := 0; i < cfg.MaxParentRecursiveDepth; i++ {
parentPom, err := getPomFromMavenRepo(groupID, artifactID, version, cfg.MavenBaseURL)
if err != nil {
return nil, err
}
parentLicenses := parseLicensesFromPom(parentPom)
if len(parentLicenses) > 0 || parentPom == nil || parentPom.Parent == nil {
licenses = parentLicenses
break
}
groupID = *parentPom.Parent.GroupID
artifactID = *parentPom.Parent.ArtifactID
version = *parentPom.Parent.Version
}
return licenses, nil
}
func getPomFromMavenRepo(groupID, artifactID, version, mavenBaseURL string) (*gopom.Project, error) {
requestURL, err := formatMavenPomURL(groupID, artifactID, version, mavenBaseURL)
if err != nil {
return nil, err
}
log.Tracef("trying to fetch parent pom from Maven central %s", requestURL)
mavenRequest, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return nil, fmt.Errorf("unable to format request for Maven central: %w", err)
}
httpClient := &http.Client{
Timeout: time.Second * 10,
}
resp, err := httpClient.Do(mavenRequest)
if err != nil {
return nil, fmt.Errorf("unable to get pom from Maven central: %w", err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
log.Errorf("unable to close body: %+v", err)
}
}()
bytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("unable to parse pom from Maven central: %w", err)
}
pom, err := decodePomXML(strings.NewReader(string(bytes)))
if err != nil {
return nil, fmt.Errorf("unable to parse pom from Maven central: %w", err)
}
return &pom, nil
}
func parseLicensesFromPom(pom *gopom.Project) []string {
var licenses []string
if pom != nil && pom.Licenses != nil {
for _, license := range *pom.Licenses {
if license.Name != nil {
licenses = append(licenses, *license.Name)
} else if license.URL != nil {
licenses = append(licenses, *license.URL)
}
}
}
return licenses
}
// discoverPkgsFromAllMavenFiles parses Maven POM properties/xml for a given
// parent package, returning all listed Java packages found for each pom
// properties discovered and potentially updating the given parentPkg with new
@@ -693,10 +597,22 @@ func newPackageFromMavenData(pomProperties pkg.JavaPomProperties, parsedPomProje
var pkgPomProject *pkg.JavaPomProject
licenses := make([]pkg.License, 0)
if parsedPomProject != nil {
if cfg.UseNetwork {
if cfg.UseNetwork {
if parsedPomProject == nil {
// If we have no pom.xml, check maven central using pom.properties
parentLicenses := recursivelyFindLicensesFromParentPom(pomProperties.GroupID, pomProperties.ArtifactID, pomProperties.Version, cfg)
if len(parentLicenses) > 0 {
for _, licenseName := range parentLicenses {
licenses = append(licenses, pkg.NewLicenseFromFields(licenseName, "", nil))
}
}
} else {
findPomLicenses(parsedPomProject, cfg)
}
}
if parsedPomProject != nil {
pkgPomProject = parsedPomProject.JavaPomProject
licenses = append(licenses, parsedPomProject.Licenses...)
}
+4 -2
View File
@@ -31,9 +31,11 @@ func NewArchiveCataloger(cfg ArchiveCatalogerConfig) *generic.Cataloger {
// NewPomCataloger returns a cataloger capable of parsing dependencies from a pom.xml file.
// Pom files list dependencies that maybe not be locally installed yet.
func NewPomCataloger() pkg.Cataloger {
func NewPomCataloger(cfg ArchiveCatalogerConfig) pkg.Cataloger {
gap := newGenericArchiveParserAdapter(cfg)
return generic.NewCataloger("java-pom-cataloger").
WithParserByGlobs(parserPomXML, "**/pom.xml")
WithParserByGlobs(gap.parserPomXML, "**/pom.xml")
}
// NewGradleLockfileCataloger returns a cataloger capable of parsing dependencies from a gradle.lockfile file.
+9 -1
View File
@@ -89,7 +89,15 @@ func Test_POMCataloger_Globs(t *testing.T) {
pkgtest.NewCatalogTester().
FromDirectory(t, test.fixture).
ExpectsResolverContentQueries(test.expected).
TestCataloger(t, NewPomCataloger())
TestCataloger(t,
NewPomCataloger(
ArchiveCatalogerConfig{
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
IncludeIndexedArchives: true,
IncludeUnindexedArchives: true,
},
},
))
})
}
}
+1 -4
View File
@@ -13,10 +13,7 @@ type ArchiveCatalogerConfig struct {
func DefaultArchiveCatalogerConfig() ArchiveCatalogerConfig {
return ArchiveCatalogerConfig{
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
IncludeIndexedArchives: true,
IncludeUnindexedArchives: false,
},
ArchiveSearchConfig: cataloging.DefaultArchiveSearchConfig(),
UseNetwork: false,
MavenBaseURL: mavenBaseURL,
MaxParentRecursiveDepth: 5,
+133
View File
@@ -0,0 +1,133 @@
package java
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
"github.com/vifraa/gopom"
"github.com/anchore/syft/internal/log"
)
func formatMavenPomURL(groupID, artifactID, version, mavenBaseURL string) (requestURL string, err error) {
// groupID needs to go from maven.org -> maven/org
urlPath := strings.Split(groupID, ".")
artifactPom := fmt.Sprintf("%s-%s.pom", artifactID, version)
urlPath = append(urlPath, artifactID, version, artifactPom)
// ex:"https://repo1.maven.org/maven2/groupID/artifactID/artifactPom
requestURL, err = url.JoinPath(mavenBaseURL, urlPath...)
if err != nil {
return requestURL, fmt.Errorf("could not construct maven url: %w", err)
}
return requestURL, err
}
// An artifact can have its version defined in a parent's DependencyManagement section
func recursivelyFindVersionFromParentPom(groupID, artifactID, parentGroupID, parentArtifactID, parentVersion string, cfg ArchiveCatalogerConfig) string {
// As there can be nested parent poms, we'll recursively check for the version until we reach the max depth
for i := 0; i < cfg.MaxParentRecursiveDepth; i++ {
parentPom, err := getPomFromMavenRepo(parentGroupID, parentArtifactID, parentVersion, cfg.MavenBaseURL)
if err != nil {
// We don't want to abort here as the parent pom might not exist in Maven Central, we'll just log the error
log.Tracef("unable to get parent pom from Maven central: %v", err)
break
}
if parentPom != nil && parentPom.DependencyManagement != nil {
for _, dependency := range *parentPom.DependencyManagement.Dependencies {
if groupID == *dependency.GroupID && artifactID == *dependency.ArtifactID && dependency.Version != nil {
return *dependency.Version
}
}
}
if parentPom == nil || parentPom.Parent == nil {
break
}
parentGroupID = *parentPom.Parent.GroupID
parentArtifactID = *parentPom.Parent.ArtifactID
parentVersion = *parentPom.Parent.Version
}
return ""
}
func recursivelyFindLicensesFromParentPom(groupID, artifactID, version string, cfg ArchiveCatalogerConfig) []string {
var licenses []string
// As there can be nested parent poms, we'll recursively check for licenses until we reach the max depth
for i := 0; i < cfg.MaxParentRecursiveDepth; i++ {
parentPom, err := getPomFromMavenRepo(groupID, artifactID, version, cfg.MavenBaseURL)
if err != nil {
// We don't want to abort here as the parent pom might not exist in Maven Central, we'll just log the error
log.Tracef("unable to get parent pom from Maven central: %v", err)
return []string{}
}
parentLicenses := parseLicensesFromPom(parentPom)
if len(parentLicenses) > 0 || parentPom == nil || parentPom.Parent == nil {
licenses = parentLicenses
break
}
groupID = *parentPom.Parent.GroupID
artifactID = *parentPom.Parent.ArtifactID
version = *parentPom.Parent.Version
}
return licenses
}
func getPomFromMavenRepo(groupID, artifactID, version, mavenBaseURL string) (*gopom.Project, error) {
requestURL, err := formatMavenPomURL(groupID, artifactID, version, mavenBaseURL)
if err != nil {
return nil, err
}
log.Tracef("trying to fetch parent pom from Maven central %s", requestURL)
mavenRequest, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return nil, fmt.Errorf("unable to format request for Maven central: %w", err)
}
httpClient := &http.Client{
Timeout: time.Second * 10,
}
resp, err := httpClient.Do(mavenRequest)
if err != nil {
return nil, fmt.Errorf("unable to get pom from Maven central: %w", err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
log.Errorf("unable to close body: %+v", err)
}
}()
bytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("unable to parse pom from Maven central: %w", err)
}
pom, err := decodePomXML(strings.NewReader(string(bytes)))
if err != nil {
return nil, fmt.Errorf("unable to parse pom from Maven central: %w", err)
}
return &pom, nil
}
func parseLicensesFromPom(pom *gopom.Project) []string {
var licenses []string
if pom != nil && pom.Licenses != nil {
for _, license := range *pom.Licenses {
if license.Name != nil {
licenses = append(licenses, *license.Name)
} else if license.URL != nil {
licenses = append(licenses, *license.URL)
}
}
}
return licenses
}
+19 -7
View File
@@ -153,6 +153,22 @@ func extractNameFromApacheMavenBundlePlugin(manifest *pkg.JavaManifest) string {
return ""
}
func extractNameFromArchiveFilename(a archiveFilename) string {
if strings.Contains(a.name, ".") {
// special case: this *might* be a group id + artifact id. By convention artifact ids do not have "." in them;
// however, there are some specific exceptions like with the artifacts under
// https://repo1.maven.org/maven2/org/eclipse/platform/
if strings.HasPrefix(a.name, "org.eclipse.") {
return a.name
}
fields := strings.Split(a.name, ".")
return fields[len(fields)-1]
}
return a.name
}
func selectName(manifest *pkg.JavaManifest, filenameObj archiveFilename) string {
name := extractNameFromApacheMavenBundlePlugin(manifest)
if name != "" {
@@ -160,13 +176,9 @@ func selectName(manifest *pkg.JavaManifest, filenameObj archiveFilename) string
}
// the filename tends to be the next-best reference for the package name
if filenameObj.name != "" {
if strings.Contains(filenameObj.name, ".") {
// special case: this *might* be a group id + artifact id. By convention artifact ids do not have "." in them.
fields := strings.Split(filenameObj.name, ".")
return fields[len(fields)-1]
}
return filenameObj.name
name = extractNameFromArchiveFilename(filenameObj)
if name != "" {
return name
}
// remaining fields in the manifest is a bit of a free-for-all depending on the build tooling used and package maintainer preferences
@@ -209,6 +209,16 @@ func TestSelectName(t *testing.T) {
archive: newJavaArchiveFilename("/something/com.atlassian.gadgets.atlassian-gadgets-api.jar"),
expected: "atlassian-gadgets-api",
},
{
desc: "Skip stripping groupId prefix from archive filename for org.eclipse",
manifest: pkg.JavaManifest{
Main: map[string]string{
"Automatic-Module-Name": "org.eclipse.ant.core",
},
},
archive: newJavaArchiveFilename("/something/org.eclipse.ant.core-3.7.0.jar"),
expected: "org.eclipse.ant.core",
},
{
// example: pkg:maven/com.google.oauth-client/google-oauth-client@1.25.0
desc: "skip Apache Maven Bundle Plugin logic if symbolic name is same as vendor id",
+25 -2
View File
@@ -24,7 +24,7 @@ const pomXMLGlob = "*pom.xml"
var propertyMatcher = regexp.MustCompile("[$][{][^}]+[}]")
func parserPomXML(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
func (gap genericArchiveParserAdapter) parserPomXML(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
pom, err := decodePomXML(reader)
if err != nil {
return nil, nil, err
@@ -36,6 +36,7 @@ func parserPomXML(_ file.Resolver, _ *generic.Environment, reader file.LocationR
p := newPackageFromPom(
pom,
dep,
gap.cfg,
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
)
if p.Name == "" {
@@ -97,7 +98,7 @@ func newPomProject(path string, p gopom.Project, location file.Location) *parsed
}
}
func newPackageFromPom(pom gopom.Project, dep gopom.Dependency, locations ...file.Location) pkg.Package {
func newPackageFromPom(pom gopom.Project, dep gopom.Dependency, cfg ArchiveCatalogerConfig, locations ...file.Location) pkg.Package {
m := pkg.JavaArchive{
PomProperties: &pkg.JavaPomProperties{
GroupID: resolveProperty(pom, dep.GroupID, "groupId"),
@@ -109,10 +110,32 @@ func newPackageFromPom(pom gopom.Project, dep gopom.Dependency, locations ...fil
name := safeString(dep.ArtifactID)
version := resolveProperty(pom, dep.Version, "version")
licenses := make([]pkg.License, 0)
if cfg.UseNetwork {
if version == "" {
// If we have no version then let's try to get it from a parent pom DependencyManagement section
version = recursivelyFindVersionFromParentPom(*dep.GroupID, *dep.ArtifactID, *pom.Parent.GroupID, *pom.Parent.ArtifactID, *pom.Parent.Version, cfg)
}
if version != "" {
parentLicenses := recursivelyFindLicensesFromParentPom(
m.PomProperties.GroupID,
m.PomProperties.ArtifactID,
version,
cfg)
if len(parentLicenses) > 0 {
for _, licenseName := range parentLicenses {
licenses = append(licenses, pkg.NewLicenseFromFields(licenseName, "", nil))
}
}
}
}
p := pkg.Package{
Name: name,
Version: version,
Locations: file.NewLocationSet(locations...),
Licenses: pkg.NewLicenseSet(licenses...),
PURL: packageURL(name, version, m),
Language: pkg.Java,
Type: pkg.JavaPkg, // TODO: should we differentiate between packages from jar/war/zip versus packages from a pom.xml that were not installed yet?
+18 -2
View File
@@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/vifraa/gopom"
"github.com/anchore/syft/syft/cataloging"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/license"
"github.com/anchore/syft/syft/pkg"
@@ -61,7 +62,15 @@ func Test_parserPomXML(t *testing.T) {
for i := range test.expected {
test.expected[i].Locations.Add(file.NewLocation(test.input))
}
pkgtest.TestFileParser(t, test.input, parserPomXML, test.expected, nil)
gap := newGenericArchiveParserAdapter(ArchiveCatalogerConfig{
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
IncludeIndexedArchives: true,
IncludeUnindexedArchives: true,
},
})
pkgtest.TestFileParser(t, test.input, gap.parserPomXML, test.expected, nil)
})
}
}
@@ -276,7 +285,14 @@ func Test_parseCommonsTextPomXMLProject(t *testing.T) {
for i := range test.expected {
test.expected[i].Locations.Add(file.NewLocation(test.input))
}
pkgtest.TestFileParser(t, test.input, parserPomXML, test.expected, nil)
gap := newGenericArchiveParserAdapter(ArchiveCatalogerConfig{
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
IncludeIndexedArchives: true,
IncludeUnindexedArchives: true,
},
})
pkgtest.TestFileParser(t, test.input, gap.parserPomXML, test.expected, nil)
})
}
}
+3 -2
View File
@@ -15,9 +15,10 @@ func NewPackageCataloger() pkg.Cataloger {
}
// NewLockCataloger returns a new cataloger object for NPM (and NPM-adjacent, such as yarn) lock files.
func NewLockCataloger() pkg.Cataloger {
func NewLockCataloger(cfg CatalogerConfig) pkg.Cataloger {
yarnLockAdapter := newGenericYarnLockAdapter(cfg)
return generic.NewCataloger("javascript-lock-cataloger").
WithParserByGlobs(parsePackageLock, "**/package-lock.json").
WithParserByGlobs(parseYarnLock, "**/yarn.lock").
WithParserByGlobs(yarnLockAdapter.parseYarnLock, "**/yarn.lock").
WithParserByGlobs(parsePnpmLock, "**/pnpm-lock.yaml")
}
@@ -132,7 +132,7 @@ func Test_JavascriptCataloger(t *testing.T) {
pkgtest.NewCatalogTester().
FromDirectory(t, "test-fixtures/pkg-lock").
Expects(expectedPkgs, nil).
TestCataloger(t, NewLockCataloger())
TestCataloger(t, NewLockCataloger(CatalogerConfig{}))
}
@@ -183,7 +183,7 @@ func Test_LockCataloger_Globs(t *testing.T) {
pkgtest.NewCatalogTester().
FromDirectory(t, test.fixture).
ExpectsResolverContentQueries(test.expected).
TestCataloger(t, NewLockCataloger())
TestCataloger(t, NewLockCataloger(CatalogerConfig{}))
})
}
}
+27
View File
@@ -0,0 +1,27 @@
package javascript
const npmBaseURL = "https://registry.npmjs.org"
type CatalogerConfig struct {
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
NPMBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
}
func DefaultCatalogerConfig() CatalogerConfig {
return CatalogerConfig{
SearchRemoteLicenses: false,
NPMBaseURL: npmBaseURL,
}
}
func (j CatalogerConfig) WithSearchRemoteLicenses(input bool) CatalogerConfig {
j.SearchRemoteLicenses = input
return j
}
func (j CatalogerConfig) WithNpmBaseURL(input string) CatalogerConfig {
if input != "" {
j.NPMBaseURL = input
}
return j
}
+76 -1
View File
@@ -2,9 +2,13 @@ package javascript
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"path"
"strings"
"time"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/internal/log"
@@ -106,13 +110,27 @@ func newPnpmPackage(resolver file.Resolver, location file.Location, name, versio
)
}
func newYarnLockPackage(resolver file.Resolver, location file.Location, name, version string) pkg.Package {
func newYarnLockPackage(cfg CatalogerConfig, resolver file.Resolver, location file.Location, name, version string) pkg.Package {
var licenseSet pkg.LicenseSet
if cfg.SearchRemoteLicenses {
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
if err == nil && license != "" {
licenses := pkg.NewLicensesFromValues(license)
licenseSet = pkg.NewLicenseSet(licenses...)
}
if err != nil {
log.Warnf("unable to extract licenses from javascript yarn.lock for package %s:%s: %+v", name, version, err)
}
}
return finalizeLockPkg(
resolver,
location,
pkg.Package{
Name: name,
Version: version,
Licenses: licenseSet,
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
PURL: packageURL(name, version),
Language: pkg.JavaScript,
@@ -121,6 +139,63 @@ func newYarnLockPackage(resolver file.Resolver, location file.Location, name, ve
)
}
func formatNpmRegistryURL(baseURL, packageName, version string) (requestURL string, err error) {
urlPath := []string{packageName, version}
requestURL, err = url.JoinPath(baseURL, urlPath...)
if err != nil {
return requestURL, fmt.Errorf("unable to format npm request for pkg:version %s%s; %w", packageName, version, err)
}
return requestURL, nil
}
func getLicenseFromNpmRegistry(basURL, packageName, version string) (string, error) {
// "https://registry.npmjs.org/%s/%s", packageName, version
requestURL, err := formatNpmRegistryURL(basURL, packageName, version)
if err != nil {
return "", fmt.Errorf("unable to format npm request for pkg:version %s%s; %w", packageName, version, err)
}
log.Tracef("trying to fetch remote package %s", requestURL)
npmRequest, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return "", fmt.Errorf("unable to format remote request: %w", err)
}
httpClient := &http.Client{
Timeout: time.Second * 10,
}
resp, err := httpClient.Do(npmRequest)
if err != nil {
return "", fmt.Errorf("unable to get package from npm registry: %w", err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
log.Errorf("unable to close body: %+v", err)
}
}()
bytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("unable to parse package from npm registry: %w", err)
}
dec := json.NewDecoder(strings.NewReader(string(bytes)))
// Read "license" from the response
var license struct {
License string `json:"license"`
}
if err := dec.Decode(&license); err != nil {
return "", fmt.Errorf("unable to parse license from npm registry: %w", err)
}
log.Tracef("Retrieved License: %s", license.License)
return license.License, nil
}
func finalizeLockPkg(resolver file.Resolver, location file.Location, p pkg.Package) pkg.Package {
licenseCandidate := addLicenses(p.Name, resolver, location)
p.Licenses.Add(pkg.NewLicensesFromLocation(location, licenseCandidate...)...)
@@ -13,9 +13,6 @@ import (
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)
// integrity check
var _ generic.Parser = parseYarnLock
var (
// packageNameExp matches the name of the dependency in yarn.lock
// including scope/namespace prefix if found.
@@ -43,7 +40,17 @@ const (
noVersion = ""
)
func parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
type genericYarnLockAdapter struct {
cfg CatalogerConfig
}
func newGenericYarnLockAdapter(cfg CatalogerConfig) genericYarnLockAdapter {
return genericYarnLockAdapter{
cfg: cfg,
}
}
func (a genericYarnLockAdapter) parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
// in the case we find yarn.lock files in the node_modules directories, skip those
// as the whole purpose of the lock file is for the specific dependencies of the project
if pathContainsNodeModulesDirectory(reader.Path()) {
@@ -62,7 +69,7 @@ func parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.L
if packageName := findPackageName(line); packageName != noPackage {
// When we find a new package, check if we have unsaved identifiers
if currentPackage != noPackage && currentVersion != noVersion && !parsedPackages.Has(currentPackage+"@"+currentVersion) {
pkgs = append(pkgs, newYarnLockPackage(resolver, reader.Location, currentPackage, currentVersion))
pkgs = append(pkgs, newYarnLockPackage(a.cfg, resolver, reader.Location, currentPackage, currentVersion))
parsedPackages.Add(currentPackage + "@" + currentVersion)
}
@@ -70,7 +77,7 @@ func parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.L
} else if version := findPackageVersion(line); version != noVersion {
currentVersion = version
} else if packageName, version := findPackageAndVersion(line); packageName != noPackage && version != noVersion && !parsedPackages.Has(packageName+"@"+version) {
pkgs = append(pkgs, newYarnLockPackage(resolver, reader.Location, packageName, version))
pkgs = append(pkgs, newYarnLockPackage(a.cfg, resolver, reader.Location, packageName, version))
parsedPackages.Add(packageName + "@" + version)
// Cleanup to indicate no unsaved identifiers
@@ -81,7 +88,7 @@ func parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.L
// check if we have valid unsaved data after end-of-file has reached
if currentPackage != noPackage && currentVersion != noVersion && !parsedPackages.Has(currentPackage+"@"+currentVersion) {
pkgs = append(pkgs, newYarnLockPackage(resolver, reader.Location, currentPackage, currentVersion))
pkgs = append(pkgs, newYarnLockPackage(a.cfg, resolver, reader.Location, currentPackage, currentVersion))
parsedPackages.Add(currentPackage + "@" + currentVersion)
}
@@ -1,6 +1,10 @@
package javascript
import (
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/assert"
@@ -91,8 +95,8 @@ func TestParseYarnBerry(t *testing.T) {
},
}
pkgtest.TestFileParser(t, fixture, parseYarnLock, expectedPkgs, expectedRelationships)
adapter := newGenericYarnLockAdapter(CatalogerConfig{})
pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships)
}
func TestParseYarnLock(t *testing.T) {
@@ -177,8 +181,62 @@ func TestParseYarnLock(t *testing.T) {
},
}
pkgtest.TestFileParser(t, fixture, parseYarnLock, expectedPkgs, expectedRelationships)
adapter := newGenericYarnLockAdapter(CatalogerConfig{})
pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships)
}
type handlerPath struct {
path string
handler func(w http.ResponseWriter, r *http.Request)
}
func TestSearchYarnForLicenses(t *testing.T) {
fixture := "test-fixtures/yarn-remote/yarn.lock"
locations := file.NewLocationSet(file.NewLocation(fixture))
mux, url, teardown := setup()
defer teardown()
tests := []struct {
name string
fixture string
config CatalogerConfig
requestHandlers []handlerPath
expectedPackages []pkg.Package
}{
{
name: "search remote licenses returns the expected licenses when search is set to true",
config: CatalogerConfig{SearchRemoteLicenses: true},
requestHandlers: []handlerPath{
{
// https://registry.yarnpkg.com/@babel/code-frame/7.10.4
path: "/@babel/code-frame/7.10.4",
handler: generateMockNPMHandler("test-fixtures/yarn-remote/registry_response.json"),
},
},
expectedPackages: []pkg.Package{
{
Name: "@babel/code-frame",
Version: "7.10.4",
Locations: locations,
PURL: "pkg:npm/%40babel/code-frame@7.10.4",
Licenses: pkg.NewLicenseSet(pkg.NewLicense("MIT")),
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// set up the mock server
for _, handler := range tc.requestHandlers {
mux.HandleFunc(handler.path, handler.handler)
}
tc.config.NPMBaseURL = url
adapter := newGenericYarnLockAdapter(tc.config)
pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, tc.expectedPackages, nil)
})
}
}
func TestParseYarnFindPackageNames(t *testing.T) {
@@ -336,3 +394,40 @@ func TestParseYarnFindPackageVersions(t *testing.T) {
})
}
}
func generateMockNPMHandler(responseFixture string) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
// Copy the file's content to the response writer
file, err := os.Open(responseFixture)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer file.Close()
_, err = io.Copy(w, file)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
}
// setup sets up a test HTTP server for mocking requests to maven central.
// The returned url is injected into the Config so the client uses the test server.
// Tests should register handlers on mux to simulate the expected request/response structure
func setup() (mux *http.ServeMux, serverURL string, teardown func()) {
// mux is the HTTP request multiplexer used with the test server.
mux = http.NewServeMux()
// We want to ensure that tests catch mistakes where the endpoint URL is
// specified as absolute rather than relative. It only makes a difference
// when there's a non-empty base URL path. So, use that. See issue #752.
apiHandler := http.NewServeMux()
apiHandler.Handle("/", mux)
// server is a test HTTP server used to provide mock API responses.
server := httptest.NewServer(apiHandler)
return mux, server.URL, server.Close
}
@@ -0,0 +1,84 @@
{
"name": "@babel/code-frame",
"version": "7.10.4",
"description": "Generate errors that contain a code frame that point to source locations.",
"author": {
"name": "Sebastian McKenzie",
"email": "sebmck@gmail.com"
},
"homepage": "https://babeljs.io/",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/babel/babel.git",
"directory": "packages/babel-code-frame"
},
"main": "lib/index.js",
"dependencies": {
"@babel/highlight": "^7.10.4"
},
"devDependencies": {
"chalk": "^2.0.0",
"strip-ansi": "^4.0.0"
},
"gitHead": "7fd40d86a0d03ff0e9c3ea16b29689945433d4df",
"bugs": {
"url": "https://github.com/babel/babel/issues"
},
"_id": "@babel/code-frame@7.10.4",
"_nodeVersion": "14.4.0",
"_npmVersion": "lerna/3.19.0/node@v14.4.0+x64 (darwin)",
"dist": {
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
"shasum": "168da1a36e90da68ae8d49c0f1b48c7c6249213a",
"tarball": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
"fileCount": 4,
"unpackedSize": 7723,
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe+zovCRA9TVsSAnZWagAAe8cQAKMtKF7FJx92Re+ol+4B\no0f3yGdzxWUhl8B+e8eXgjYcetMe1MZpG1oQF5ocYo45mZ+ASWMzfp1caT1p\nqt3F5rtADrL9int8ti7ICrWkIGQ3ccnrTxmtx1y9NRGANeARYjlB538xg0xy\n2Gin+2NchK2gxkxeX0nPH7LOcLlJpXecv1p2BK8gFZfabhM4fKfcMSSeljUp\ngzBGU/0CQp3++KsFAS/GMtgo6ZLw7wnHn0IVtDbwhA6A7hpDZar1Q5xsleui\nUTFIJCegGBx9exO1z0fYLGjOuvOdB5790fQnGsspbVTMwpImWpjspmuH1kWI\nTtk1ocnUnvEu1wNK2FMspUeKHNmOi5Jr6bkdGTxecXV4W/p9oEoPe3tHItL5\nbG9gNxY4IUkHeL93D86w9DtgaYtFSCYD6+sY7mQQQdhBrilR06AugBtQG3jP\nFpEsOLSn8vhYOQKv18CN//xaJM/uar40NTfZcQTn4VLXjUsuR4W+3eAv+qb+\nSKEpf8YAhgXJR5EFG1m3m4VHCp40SM1oSibh3/Ib74VZmlF/aq0VcPDs9tD2\no/MibYbQcP01cYxzpfObPXRczTH8TSl3scslcf7aVcLuhbyJtw8gblKnmXjo\njNaZrKjGKrpKRYStMBbCt8ILkL+OZTcDJcihy1x0v4oOWT43lrHnPntOAg7D\nqQbp\r\n=RhVa\r\n-----END PGP SIGNATURE-----\r\n",
"signatures": [
{
"keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
"sig": "MEUCIQDSjBYOah3mnIxnAjEKv638MySMCxhZ0J9pexriecmdogIgAOaTRZg3UeVxrs8Khzr78+n4T+10hMn2Z9DRR7k5qEM="
}
]
},
"maintainers": [
{
"email": "daniel@tschinder.de",
"name": "danez"
},
{
"email": "bng412@gmail.com",
"name": "existentialism"
},
{
"email": "hi@henryzoo.com",
"name": "hzoo"
},
{
"email": "i@jhuang.me",
"name": "jlhwung"
},
{
"email": "loganfsmyth@gmail.com",
"name": "loganfsmyth"
},
{
"email": "nicolo.ribaudo@gmail.com",
"name": "nicolo-ribaudo"
}
],
"_npmUser": {
"name": "jlhwung",
"email": "i@jhuang.me"
},
"directories": {},
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/code-frame_7.10.4_1593522734690_0.6416145193889038"
},
"_hasShrinkwrap": false
}
@@ -0,0 +1,10 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
dependencies:
"@babel/highlight" "^7.10.4"
+33 -2
View File
@@ -4,6 +4,8 @@ import (
"fmt"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/internal/licenses"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
)
@@ -55,13 +57,42 @@ func newPackageForRequirementsWithMetadata(name, version string, metadata pkg.Py
return p
}
func newPackageForPackage(m parsedData, sources ...file.Location) pkg.Package {
func newPackageForPackage(resolver file.Resolver, m parsedData, sources ...file.Location) pkg.Package {
var licenseSet pkg.LicenseSet
switch {
case m.LicenseExpression != "":
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.LicenseExpression)...)
case m.Licenses != "":
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.Licenses)...)
case m.LicenseLocation.Path() != "":
// If we have a license file then resolve and parse it
found, err := resolver.FilesByPath(m.LicenseLocation.Path())
if err != nil {
log.WithFields("error", err).Tracef("unable to resolve python license path %s", m.LicenseLocation.Path())
}
if len(found) > 0 {
metadataContents, err := resolver.FileContentsByLocation(found[0])
if err == nil {
parsed, err := licenses.Parse(metadataContents, m.LicenseLocation)
if err != nil {
log.WithFields("error", err).Tracef("unable to parse a license from the file in %s", m.LicenseLocation.Path())
}
if len(parsed) > 0 {
licenseSet = pkg.NewLicenseSet(parsed...)
}
} else {
log.WithFields("error", err).Tracef("unable to read file contents at %s", m.LicenseLocation.Path())
}
}
}
p := pkg.Package{
Name: m.Name,
Version: m.Version,
PURL: packageURL(m.Name, m.Version, &m.PythonPackage),
Locations: file.NewLocationSet(sources...),
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.Licenses)...),
Licenses: licenseSet,
Language: pkg.Python,
Type: pkg.PythonPkg,
Metadata: m.PythonPackage,
+1 -1
View File
@@ -32,7 +32,7 @@ func parseWheelOrEgg(resolver file.Resolver, _ *generic.Environment, reader file
return nil, nil, nil
}
pkgs := []pkg.Package{newPackageForPackage(*pd, sources...)}
pkgs := []pkg.Package{newPackageForPackage(resolver, *pd, sources...)}
return pkgs, nil, nil
}
@@ -17,6 +17,8 @@ import (
type parsedData struct {
Licenses string `mapstructure:"License"`
LicenseFile string `mapstructure:"LicenseFile"`
LicenseExpression string `mapstructure:"LicenseExpression"`
LicenseLocation file.Location
pkg.PythonPackage `mapstructure:",squash"`
}
@@ -80,8 +82,10 @@ func parseWheelOrEggMetadata(path string, reader io.Reader) (parsedData, error)
// add additional metadata not stored in the egg/wheel metadata file
pd.SitePackagesRootPath = determineSitePackagesRootPath(path)
if pd.Licenses != "" {
if pd.Licenses != "" || pd.LicenseExpression != "" {
pd.LicenseLocation = file.NewLocation(path)
} else if pd.LicenseFile != "" {
pd.LicenseLocation = file.NewLocation(filepath.Join(filepath.Dir(path), pd.LicenseFile))
}
return pd, nil
@@ -19,6 +19,8 @@ func TestParseWheelEggMetadata(t *testing.T) {
Fixture: "test-fixtures/egg-info/PKG-INFO",
ExpectedMetadata: parsedData{
"Apache 2.0",
"",
"",
file.NewLocation("test-fixtures/egg-info/PKG-INFO"),
pkg.PythonPackage{
Name: "requests",
@@ -34,6 +36,8 @@ func TestParseWheelEggMetadata(t *testing.T) {
Fixture: "test-fixtures/dist-info/METADATA",
ExpectedMetadata: parsedData{
"BSD License",
"",
"",
file.NewLocation("test-fixtures/dist-info/METADATA"),
pkg.PythonPackage{
Name: "Pygments",
@@ -134,6 +138,8 @@ func TestParseWheelEggMetadataInvalid(t *testing.T) {
{
Fixture: "test-fixtures/egg-info/PKG-INFO-INVALID",
ExpectedMetadata: parsedData{
"",
"",
"",
file.Location{},
pkg.PythonPackage{
+30 -25
View File
@@ -21,7 +21,7 @@ type Collection struct {
// NewCollection returns a new empty Collection
func NewCollection(pkgs ...Package) *Collection {
catalog := Collection{
c := Collection{
byID: make(map[artifact.ID]Package),
idsByName: make(map[string]orderedIDSet),
idsByType: make(map[Type]orderedIDSet),
@@ -29,10 +29,10 @@ func NewCollection(pkgs ...Package) *Collection {
}
for _, p := range pkgs {
catalog.Add(p)
c.Add(p)
}
return &catalog
return &c
}
// PackageCount returns the total number of packages that have been added.
@@ -97,32 +97,37 @@ func (c *Collection) packages(ids []artifact.ID) (result []Package) {
return result
}
// Add n packages to the catalog.
// Add n packages to the collection.
func (c *Collection) Add(pkgs ...Package) {
for _, p := range pkgs {
c.add(p)
}
}
// Add a package to the Collection.
func (c *Collection) add(p Package) {
c.lock.Lock()
defer c.lock.Unlock()
for _, p := range pkgs {
id := p.ID()
if id == "" {
log.Warnf("found package with empty ID while adding to the catalog: %+v", p)
p.SetID()
id = p.ID()
}
if existing, exists := c.byID[id]; exists {
// there is already a package with this fingerprint merge the existing record with the new one
if err := existing.merge(p); err != nil {
log.Warnf("failed to merge packages: %+v", err)
} else {
c.byID[id] = existing
c.addPathsToIndex(p)
}
return
}
c.addToIndex(p)
id := p.ID()
if id == "" {
log.Warnf("found package with empty ID while adding to the collection: %+v", p)
p.SetID()
id = p.ID()
}
if existing, exists := c.byID[id]; exists {
// there is already a package with this fingerprint merge the existing record with the new one
if err := existing.merge(p); err != nil {
log.Warnf("failed to merge packages: %+v", err)
} else {
c.byID[id] = existing
c.addPathsToIndex(p)
}
return
}
c.addToIndex(p)
}
func (c *Collection) addToIndex(p Package) {
@@ -242,7 +247,7 @@ func (c *Collection) Enumerate(types ...Type) <-chan Package {
defer close(channel)
if c == nil {
// we should allow enumerating from a catalog that was never created (which will result in no packages enumerated)
// we should allow enumerating from a collection that was never created (which will result in no packages enumerated)
return
}
+1 -1
View File
@@ -189,7 +189,7 @@ func (s FileSource) FileResolver(_ Scope) (file.Resolver, error) {
return fs.SkipDir
}
if path.Base(p) != path.Base(s.config.Path) {
if filepath.Base(p) != filepath.Base(s.config.Path) {
// we're in the root directory, but this is not the file we want to scan...
// we should selectively skip this file (not the directory we're in).
return fileresolver.ErrSkipPath
+605 -163
View File
@@ -17,8 +17,14 @@ func TestJavaPURLs(t *testing.T) {
if p.Type != pkg.JavaPkg && p.Type != pkg.JenkinsPluginPkg {
continue
}
key := fmt.Sprintf("%s@%s", p.Name, p.Version)
found[key] = p.PURL
if metadata, ok := p.Metadata.(pkg.JavaArchive); ok {
if _, ok := noAssertion[metadata.VirtualPath]; ok {
continue
}
found[metadata.VirtualPath] = p.PURL
}
}
for key, expectedPURL := range expectedPURLs {
purl := found[key]
@@ -30,168 +36,604 @@ func TestJavaPURLs(t *testing.T) {
}
}
// This is for artifacts that either don't have a known groupid/artifactid
// since they aren't available on a known maven repository, or where syft is currently
// generating the incorrect PURL
var noAssertion = map[string]string{
// These are not known to exist on any public maven repo, so no real PURL should be asserted
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/jopenssl.jar": "pkg:maven/jopenssl/jopenssl",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/json/ext/generator.jar": "pkg:maven/generator/generator",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/json/ext/parser.jar": "pkg:maven/parser/parser",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/psych.jar": "pkg:maven/psych/psych",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/racc/cparse-jruby.jar": "pkg:maven/cparse-jruby/cparse-jruby",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/readline.jar": "pkg:maven/readline/readline",
"/packages/org.eclipse.ant.core-3.7.0.jar:lib/antsupportlib.jar": "pkg:maven/antsupportlib/antsupportlib",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar": "pkg:maven/sdk/sdk@3.0",
// syft generates incorrect purls
"/packages/kafka_2.13-3.2.2.jar": "pkg:maven/org.apache.kafka/kafka_2.13@3.2.2",
"/packages/akka-actor_2.13-2.6.6.jar": "pkg:maven/com.typesafe.akka/akka-actor_2.13@2.6.6",
"/packages/akka-management-cluster-bootstrap_2.13-1.2.0.jar": "pkg:maven/com.lightbend.akka.management/akka-management-cluster-bootstrap_2.13@1.2.0",
"/packages/hudson.war:WEB-INF/lib/asm-2.2.3.jar": "pkg:maven/asm/asm@2.2.3",
"/packages/hudson.war:WEB-INF/lib/asm-commons-2.2.3.jar": "pkg:maven/asm/asm-commons@2.2.3",
"/packages/hudson.war:WEB-INF/lib/asm-tree-2.2.3.jar": "pkg:maven/asm/asm-tree@2.2.3",
"/packages/hudson.war:WEB-INF/slave.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
"/packages/hudson.war:WEB-INF/lib/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3_min/xpp3_min@1.1.4c",
"/packages/hudson.war:WEB-INF/lib/xpp3-1.1.4c.jar": "pkg:maven/xpp3/xpp3@1.1.4c",
"/packages/hudson.war:WEB-INF/hudson-cli.jar": "pkg:maven/org.jvnet.hudson.main/hudson-cli@1.390",
"/packages/hudson.war:WEB-INF/lib/dom4j-1.6.1-hudson-3.jar": "pkg:maven/org.jvnet.hudson.dom4j/dom4j@1.6.1-hudson-3",
"/packages/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3/xpp3_min@1.1.4c",
// syft generates an unstable purl
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-auth": "pkg:maven/org.apache.dubbo/dubbo-auth@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-cluster": "pkg:maven/org.apache.dubbo/dubbo-cluster@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-common": "pkg:maven/org.apache.dubbo/dubbo-common@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-compatible": "pkg:maven/org.apache.dubbo/dubbo-compatible@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-config-api": "pkg:maven/org.apache.dubbo/dubbo-config-api@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-config-spring": "pkg:maven/org.apache.dubbo/dubbo-config-spring@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-apollo": "pkg:maven/org.apache.dubbo/dubbo-configcenter-apollo@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-nacos": "pkg:maven/org.apache.dubbo/dubbo-configcenter-nacos@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-configcenter-zookeeper@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-container-api": "pkg:maven/org.apache.dubbo/dubbo-container-api@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-container-spring": "pkg:maven/org.apache.dubbo/dubbo-container-spring@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-filter-cache": "pkg:maven/org.apache.dubbo/dubbo-filter-cache@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-filter-validation": "pkg:maven/org.apache.dubbo/dubbo-filter-validation@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-kubernetes": "pkg:maven/org.apache.dubbo/dubbo-kubernetes@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-api": "pkg:maven/org.apache.dubbo/dubbo-metadata-api@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-definition-protobuf": "pkg:maven/org.apache.dubbo/dubbo-metadata-definition-protobuf@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-nacos": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-nacos@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-redis": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-redis@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-zookeeper@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metrics-api": "pkg:maven/org.apache.dubbo/dubbo-metrics-api@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metrics-prometheus": "pkg:maven/org.apache.dubbo/dubbo-metrics-prometheus@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-monitor-api": "pkg:maven/org.apache.dubbo/dubbo-monitor-api@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-monitor-default": "pkg:maven/org.apache.dubbo/dubbo-monitor-default@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-qos": "pkg:maven/org.apache.dubbo/dubbo-qos@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-reactive": "pkg:maven/org.apache.dubbo/dubbo-reactive@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-api": "pkg:maven/org.apache.dubbo/dubbo-registry-api@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-multicast": "pkg:maven/org.apache.dubbo/dubbo-registry-multicast@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-multiple": "pkg:maven/org.apache.dubbo/dubbo-registry-multiple@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-nacos": "pkg:maven/org.apache.dubbo/dubbo-registry-nacos@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-registry-zookeeper@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-api": "pkg:maven/org.apache.dubbo/dubbo-remoting-api@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-http": "pkg:maven/org.apache.dubbo/dubbo-remoting-http@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-netty": "pkg:maven/org.apache.dubbo/dubbo-remoting-netty@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-netty4": "pkg:maven/org.apache.dubbo/dubbo-remoting-netty4@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-remoting-zookeeper@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-zookeeper-curator5": "pkg:maven/org.apache.dubbo/dubbo-remoting-zookeeper-curator5@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-api": "pkg:maven/org.apache.dubbo/dubbo-rpc-api@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-dubbo": "pkg:maven/org.apache.dubbo/dubbo-rpc-dubbo@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-grpc": "pkg:maven/org.apache.dubbo/dubbo-rpc-grpc@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-injvm": "pkg:maven/org.apache.dubbo/dubbo-rpc-injvm@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-rest": "pkg:maven/org.apache.dubbo/dubbo-rpc-rest@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-triple": "pkg:maven/org.apache.dubbo/dubbo-rpc-triple@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-api": "pkg:maven/org.apache.dubbo/dubbo-serialization-api@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-fastjson2": "pkg:maven/org.apache.dubbo/dubbo-serialization-fastjson2@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-hessian2": "pkg:maven/org.apache.dubbo/dubbo-serialization-hessian2@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-jdk": "pkg:maven/org.apache.dubbo/dubbo-serialization-jdk@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-xds": "pkg:maven/org.apache.dubbo/dubbo-xds@3.1.4",
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
"/packages/dubbo-3.1.4.jar": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
}
// Constructed by:
// syft anchore/test_images:java-56d52bc -o template -t /tmp/test.templ | grep 'pkg:maven' | sort | uniq >> test/integration/java_purl_test.go
// where the template is:
/*
{{ range .Artifacts}}"{{.Name}}@{{.Version}}":"{{.PURL}}",
{{ end }}
*/
// syft anchore/test_images:java-1abc58f -o json | jq -r '.artifacts.[] | [.metadata.virtualPath, .purl, ""] | @csv' | grep 'pkg:maven' | sort | uniq >> /tmp/java_artifacts_mapping.txt
// The map was then hand-edited for correctness by comparing to Maven Central.
var expectedPURLs = map[string]string{
"TwilioNotifier@0.2.1": "pkg:maven/com.twilio.jenkins/TwilioNotifier@0.2.1",
"access-modifier-annotation@1.0": "pkg:maven/org.kohsuke/access-modifier-annotation@1.0",
"acegi-security@1.0.5": "pkg:maven/org.acegisecurity/acegi-security@1.0.5",
"activation@1.1.1-hudson-1": "pkg:maven/org.jvnet.hudson/activation@1.1.1-hudson-1",
"akuma@1.2": "pkg:maven/com.sun.akuma/akuma@1.2",
"animal-sniffer-annotation@1.0": "pkg:maven/org.jvnet/animal-sniffer-annotation@1.0",
"annotation-indexer@1.2": "pkg:maven/org.jvnet.hudson/annotation-indexer@1.2",
"annotations@13.0": "pkg:maven/org.jetbrains/annotations@13.0",
"ant-launcher@1.8.0": "pkg:maven/org.apache.ant/ant-launcher@1.8.0",
"ant@1.8.0": "pkg:maven/org.apache.ant/ant@1.8.0",
"antlr@2.7.6": "pkg:maven/antlr/antlr@2.7.6",
"aopalliance@1.0": "pkg:maven/aopalliance/aopalliance@1.0",
"args4j@2.0.16": "pkg:maven/args4j/args4j@2.0.16",
"asm-commons@2.2.3": "pkg:maven/asm-commons/asm-commons@2.2.3",
"asm-tree@2.2.3": "pkg:maven/asm-tree/asm-tree@2.2.3",
"asm@2.2.3": "pkg:maven/asm/asm@2.2.3",
"avalon-framework@4.1.3": "pkg:maven/avalon-framework/avalon-framework@4.1.3",
"bridge-method-annotation@1.2": "pkg:maven/com.infradna.tool/bridge-method-annotation@1.2",
"classworlds@1.1": "pkg:maven/org.codehaus.classworlds/classworlds@1.1",
"cli@1.390": "pkg:maven/org.jvnet.hudson.main/cli@1.390",
"commons-beanutils@1.8.0": "pkg:maven/commons-beanutils/commons-beanutils@1.8.0",
"commons-codec@1.2": "pkg:maven/commons-codec/commons-codec@1.2",
"commons-codec@1.4": "pkg:maven/commons-codec/commons-codec@1.4",
"commons-collections@3.2": "pkg:maven/commons-collections/commons-collections@3.2",
"commons-digester@1.7": "pkg:maven/commons-digester/commons-digester@1.7",
"commons-discovery@0.4": "pkg:maven/commons-discovery/commons-discovery@0.4",
"commons-fileupload@1.2.1": "pkg:maven/commons-fileupload/commons-fileupload@1.2.1",
"commons-httpclient@3.1": "pkg:maven/org.apache/commons-httpclient@3.1",
"commons-httpclient@3.1-rc1": "pkg:maven/commons-httpclient/commons-httpclient@3.1-rc1",
"commons-io@1.4": "pkg:maven/commons-io/commons-io@1.4",
"commons-jelly-tags-define@1.0.1-hudson-20071021": "pkg:maven/org.jvnet.hudson/commons-jelly-tags-define@1.0.1-hudson-20071021",
"commons-jelly-tags-fmt@1.0": "pkg:maven/commons-jelly-tags-fmt/commons-jelly-tags-fmt@1.0",
"commons-jelly-tags-xml@1.1": "pkg:maven/commons-jelly-tags-xml/commons-jelly-tags-xml@1.1",
"commons-jelly@1.1-hudson-20100305": "pkg:maven/org.jvnet.hudson/commons-jelly@1.1-hudson-20100305",
"commons-jexl@1.1-hudson-20090508": "pkg:maven/org.jvnet.hudson/commons-jexl@1.1-hudson-20090508",
"commons-lang@2.4": "pkg:maven/commons-lang/commons-lang@2.4",
"commons-lang@2.5": "pkg:maven/commons-lang/commons-lang@2.5",
"commons-logging@1.0.4": "pkg:maven/commons-logging/commons-logging@1.0.4", // see https://mvnrepository.com/artifact/commons-logging/commons-logging/1.0.4
"commons-logging@1.1": "pkg:maven/commons-logging/commons-logging@1.1", // see https://mvnrepository.com/artifact/commons-logging/commons-logging/1.1
"commons-logging@1.1.1": "pkg:maven/commons-logging/commons-logging@1.1.1", // see https://mvnrepository.com/artifact/commons-logging/commons-logging/1.1.1
"commons-pool@1.3": "pkg:maven/commons-pool/commons-pool@1.3",
"crypto-util@1.0": "pkg:maven/org.jvnet.hudson/crypto-util@1.0",
"cvs@1.2": "pkg:maven/org.jvnet.hudson.plugins/cvs@1.2",
"dom4j@1.6.1-hudson-3": "pkg:maven/dom4j/dom4j@1.6.1-hudson-3",
"doxia-sink-api@1.0-alpha-10": "pkg:maven/org.apache.maven.doxia/doxia-sink-api@1.0-alpha-10",
"easymock@2.4": "pkg:maven/org.easymock/easymock@2.4",
"embedded_su4j@1.1": "pkg:maven/com.sun.solaris/embedded_su4j@1.1",
"example-java-app-gradle@0.1.0": "pkg:maven/example-java-app-gradle/example-java-app-gradle@0.1.0",
"ezmorph@1.0.3": "pkg:maven/net.sf.ezmorph/ezmorph@1.0.3",
"graph-layouter@1.0": "pkg:maven/org.kohsuke/graph-layouter@1.0",
"groovy-all@1.6.0": "pkg:maven/groovy-all/groovy-all@1.6.0",
"gson@2.8.6": "pkg:maven/com.google.code.gson/gson@2.8.6",
"guava@r06": "pkg:maven/com.google.guava/guava@r06",
"httpclient@4.1.1": "pkg:maven/org.apache.httpcomponents/httpclient@4.1.1",
"httpcore@4.1": "pkg:maven/org.apache.httpcomponents/httpcore@4.1",
"hudson-cli@": "pkg:maven/hudson-cli/hudson-cli",
"hudson-core@1.390": "pkg:maven/org.jvnet.hudson.main/hudson-core@1.390",
"hudson-war@1.390": "pkg:maven/org.jvnet.hudson.main/hudson-war@1.390",
"j-interop@2.0.5": "pkg:maven/j-interop/j-interop@2.0.5",
"j-interopdeps@2.0.5": "pkg:maven/j-interopdeps/j-interopdeps@2.0.5",
"jaxen@1.1-beta-11": "pkg:maven/org.jaxen/jaxen@1.1-beta-11",
"jcaptcha-all@1.0-RC6": "pkg:maven/jcaptcha-all/jcaptcha-all@1.0-RC6",
"jcifs@1.3.14-kohsuke-1": "pkg:maven/org.samba.jcifs/jcifs@1.3.14-kohsuke-1",
"jcommon@1.0.12": "pkg:maven/jfree/jcommon@1.0.12",
"jfreechart@1.0.9": "pkg:maven/jfreechart/jfreechart@1.0.9",
"jinterop-proxy@1.1": "pkg:maven/org.kohsuke.jinterop/jinterop-proxy@1.1",
"jinterop-wmi@1.0": "pkg:maven/org.jvnet.hudson/jinterop-wmi@1.0",
"jline@0.9.94": "pkg:maven/jline/jline@0.9.94",
"jmdns@3.1.6-hudson-2": "pkg:maven/com.strangeberry.jmdns.tools.Main/jmdns@3.1.6-hudson-2",
"jna-posix@1.0.3": "pkg:maven/org.jruby.ext.posix/jna-posix@1.0.3",
"jna@3.2.4": "pkg:maven/com.sun.jna/jna@3.2.4",
"jsch@0.1.27": "pkg:maven/jsch/jsch@0.1.27",
"json-lib@2.1-rev6": "pkg:maven/json-lib/json-lib@2.1-rev6",
"json@20200518": "pkg:maven/org.json/json@20200518",
"jstl@1.1.0": "pkg:maven/com.sun/jstl@1.1.0",
"jtidy@4aug2000r7-dev-hudson-1": "pkg:maven/jtidy/jtidy@4aug2000r7-dev-hudson-1",
"junit@4.13.1": "pkg:maven/junit/junit@4.13.1",
"kotlin-stdlib-common@1.3.70": "pkg:maven/kotlin-stdlib-common/kotlin-stdlib-common@1.3.70",
"kotlin-stdlib@1.3.70": "pkg:maven/kotlin-stdlib/kotlin-stdlib@1.3.70",
"libpam4j@1.2": "pkg:maven/org.jvnet.libpam4j/libpam4j@1.2",
"libzfs@0.5": "pkg:maven/org.jvnet.libzfs/libzfs@0.5",
"localizer@1.10": "pkg:maven/org.jvnet.localizer/localizer@1.10",
"log4j@1.2.9": "pkg:maven/log4j/log4j@1.2.9",
"logkit@1.0.1": "pkg:maven/logkit/logkit@1.0.1",
"mail@1.4": "pkg:maven/com.sun/mail@1.4",
"maven-agent@1.390": "pkg:maven/org.jvnet.hudson.main/maven-agent@1.390",
"maven-artifact-manager@2.0.9": "pkg:maven/org.apache.maven/maven-artifact-manager@2.0.9",
"maven-artifact@2.0.9": "pkg:maven/org.apache.maven/maven-artifact@2.0.9",
"maven-core@2.0.9": "pkg:maven/org.apache.maven/maven-core@2.0.9",
"maven-embedder@2.0.4": "pkg:maven/org.apache.maven/maven-embedder@2.0.4",
"maven-embedder@2.0.4-hudson-1": "pkg:maven/org.jvnet.hudson/maven-embedder@2.0.4-hudson-1",
"maven-error-diagnostics@2.0.9": "pkg:maven/org.apache.maven/maven-error-diagnostics@2.0.9",
"maven-interceptor@1.390": "pkg:maven/org.jvnet.hudson.main/maven-interceptor@1.390",
"maven-model@2.0.9": "pkg:maven/org.apache.maven/maven-model@2.0.9",
"maven-monitor@2.0.9": "pkg:maven/org.apache.maven/maven-monitor@2.0.9",
"maven-plugin-api@2.0.9": "pkg:maven/org.apache.maven/maven-plugin-api@2.0.9",
"maven-plugin-descriptor@2.0.9": "pkg:maven/org.apache.maven/maven-plugin-descriptor@2.0.9",
"maven-plugin-parameter-documenter@2.0.9": "pkg:maven/org.apache.maven/maven-plugin-parameter-documenter@2.0.9",
"maven-plugin-registry@2.0.9": "pkg:maven/org.apache.maven/maven-plugin-registry@2.0.9",
"maven-plugin@1.390": "pkg:maven/org.jvnet.hudson.main/maven-plugin@1.390",
"maven-profile@2.0.9": "pkg:maven/org.apache.maven/maven-profile@2.0.9",
"maven-project@2.0.9": "pkg:maven/org.apache.maven/maven-project@2.0.9",
"maven-reporting-api@2.0.9": "pkg:maven/org.apache.maven.reporting/maven-reporting-api@2.0.9",
"maven-repository-metadata@2.0.9": "pkg:maven/org.apache.maven/maven-repository-metadata@2.0.9",
"maven-settings@2.0.9": "pkg:maven/org.apache.maven/maven-settings@2.0.9",
"maven2.1-interceptor@1.2": "pkg:maven/org.jvnet.hudson/maven2.1-interceptor@1.2",
"memory-monitor@1.3": "pkg:maven/org.jvnet.hudson/memory-monitor@1.3",
"nomad@0.7.4": "pkg:maven/org.jenkins-ci.plugins/nomad@0.7.4",
"okhttp@4.5.0": "pkg:maven/com.squareup.okhttp3/okhttp@4.5.0",
"okio@2.5.0": "pkg:maven/com.squareup.okio/okio@2.5.0",
"oro@2.0.8": "pkg:maven/org.apache.oro/oro@2.0.8",
"plexus-container-default@1.0-alpha-9-stable-1": "pkg:maven/org.codehaus.plexus/plexus-container-default@1.0-alpha-9-stable-1",
"plexus-interactivity-api@1.0-alpha-4": "pkg:maven/org.codehaus.plexus/plexus-interactivity-api@1.0-alpha-4",
"plexus-utils@1.5.1": "pkg:maven/org.codehaus.plexus/plexus-utils@1.5.1",
"remoting@1.390": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
"robust-http-client@1.1": "pkg:maven/org.jvnet.robust-http-client/robust-http-client@1.1",
"sdk@3.0": "pkg:maven/sdk/sdk@3.0",
"sezpoz@1.7": "pkg:maven/net.java.sezpoz/sezpoz@1.7",
"slave@": "pkg:maven/slave/slave",
"slide-webdavlib@2.1": "pkg:maven/slide-webdavlib/slide-webdavlib@2.1",
"spring-aop@2.5": "pkg:maven/org.springframework/spring-aop@2.5",
"spring-beans@2.5": "pkg:maven/org.springframework/spring-beans@2.5",
"spring-context@2.5": "pkg:maven/org.springframework/spring-context@2.5",
"spring-core@2.5": "pkg:maven/org.springframework/spring-core@2.5",
"spring-dao@1.2.9": "pkg:maven/org.springframework/spring-dao@1.2.9",
"spring-jdbc@1.2.9": "pkg:maven/org.springframework/spring-jdbc@1.2.9",
"spring-web@2.5": "pkg:maven/org.springframework/spring-web@2.5",
"ssh-slaves@0.14": "pkg:maven/org.jvnet.hudson.plugins/ssh-slaves@0.14",
"stapler-adjunct-timeline@1.2": "pkg:maven/org.kohsuke.stapler/stapler-adjunct-timeline@1.2",
"stapler-jelly@1.155": "pkg:maven/org.kohsuke.stapler/stapler-jelly@1.155",
"stapler@1.155": "pkg:maven/org.kohsuke.stapler/stapler@1.155",
"stax-api@1.0.1": "pkg:maven/stax-api/stax-api@1.0.1",
"subversion@1.20": "pkg:maven/org.jvnet.hudson.plugins/subversion@1.20",
"svnkit@1.3.4-hudson-2": "pkg:maven/svnkit/svnkit@1.3.4-hudson-2",
"task-reactor@1.2": "pkg:maven/org.jvnet.hudson/task-reactor@1.2",
"tiger-types@1.3": "pkg:maven/org.jvnet/tiger-types@1.3",
"trilead-putty-extension@1.0": "pkg:maven/org.kohsuke/trilead-putty-extension@1.0",
"trilead-ssh2@build212-hudson-5": "pkg:maven/org.jvnet.hudson/trilead-ssh2@build212-hudson-5",
"txw2@20070624": "pkg:maven/txw2/txw2@20070624",
"wagon-file@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-file@1.0-beta-2",
"wagon-http-lightweight@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-http-lightweight@1.0-beta-2",
"wagon-http-shared@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-http-shared@1.0-beta-2",
"wagon-provider-api@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-provider-api@1.0-beta-2",
"wagon-ssh-common@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-ssh-common@1.0-beta-2",
"wagon-ssh-external@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-ssh-external@1.0-beta-2",
"wagon-ssh@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-ssh@1.0-beta-2",
"wagon-webdav@1.0-beta-2-hudson-1": "pkg:maven/org.jvnet.hudson/wagon-webdav@1.0-beta-2-hudson-1",
"windows-remote-command@1.0": "pkg:maven/org.jvnet.hudson/windows-remote-command@1.0",
"winp@1.14": "pkg:maven/org.jvnet.winp/winp@1.14",
"winstone@0.9.10-hudson-24": "pkg:maven/org.jvnet.hudson.winstone/winstone@0.9.10-hudson-24",
"wstx-asl@3.2.7": "pkg:maven/wstx-asl/wstx-asl@3.2.7",
"xml-im-exporter@1.1": "pkg:maven/xml-im-exporter/xml-im-exporter@1.1",
"xpp3@1.1.4c": "pkg:maven/xpp3/xpp3@1.1.4c",
"xpp3_min@1.1.4c": "pkg:maven/xpp3_min/xpp3_min@1.1.4c",
"xstream@1.3.1-hudson-8": "pkg:maven/org.jvnet.hudson/xstream@1.3.1-hudson-8",
"/packages/activemq-client-5.18.2.jar": "pkg:maven/org.apache.activemq/activemq-client@5.18.2",
"/packages/activemq-protobuf-1.1.jar": "pkg:maven/org.apache.activemq.protobuf/activemq-protobuf@1.1",
// "/packages/akka-actor_2.13-2.6.6.jar": "pkg:maven/com.typesafe.akka/akka-actor_2.13@2.6.6",
// "/packages/akka-management-cluster-bootstrap_2.13-1.2.0.jar": "pkg:maven/com.lightbend.akka.management/akka-management-cluster-bootstrap_2.13@1.2.0",
"/packages/ant-1.10.3.jar": "pkg:maven/org.apache.ant/ant@1.10.3",
"/packages/apache-chainsaw-2.1.0.jar": "pkg:maven/log4j/apache-chainsaw@2.1.0",
"/packages/apache-log4j-extras-1.1.jar": "pkg:maven/log4j/apache-log4j-extras@1.1",
"/packages/apoc-4.4.0.11.jar": "pkg:maven/org.neo4j.procedure/apoc@4.4.0.11",
"/packages/bc-fips-1.0.2.3.jar": "pkg:maven/org.bouncycastle/bc-fips@1.0.2.3",
"/packages/camel-core-3.1.0.jar": "pkg:maven/org.apache.camel/camel-core@3.1.0",
"/packages/cassandra-all-4.1.1.jar": "pkg:maven/org.apache.cassandra/cassandra-all@4.1.1",
"/packages/commons-logging-1.1.1.jar": "pkg:maven/commons-logging/commons-logging@1.1.1",
"/packages/commons-vfs-1.0.jar": "pkg:maven/commons-vfs/commons-vfs@1.0",
"/packages/cxf-rt-transports-http-2.7.3.jar": "pkg:maven/org.apache.cxf/cxf-rt-transports-http@2.7.3",
"/packages/dubbo-3.1.4.jar:com.alibaba:hessian-lite": "pkg:maven/com.alibaba/hessian-lite@3.2.13",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-auth": "pkg:maven/org.apache.dubbo/dubbo-auth@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-cluster": "pkg:maven/org.apache.dubbo/dubbo-cluster@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-common": "pkg:maven/org.apache.dubbo/dubbo-common@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-compatible": "pkg:maven/org.apache.dubbo/dubbo-compatible@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-config-api": "pkg:maven/org.apache.dubbo/dubbo-config-api@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-config-spring": "pkg:maven/org.apache.dubbo/dubbo-config-spring@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-apollo": "pkg:maven/org.apache.dubbo/dubbo-configcenter-apollo@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-nacos": "pkg:maven/org.apache.dubbo/dubbo-configcenter-nacos@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-configcenter-zookeeper@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-container-api": "pkg:maven/org.apache.dubbo/dubbo-container-api@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-container-spring": "pkg:maven/org.apache.dubbo/dubbo-container-spring@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-filter-cache": "pkg:maven/org.apache.dubbo/dubbo-filter-cache@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-filter-validation": "pkg:maven/org.apache.dubbo/dubbo-filter-validation@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-kubernetes": "pkg:maven/org.apache.dubbo/dubbo-kubernetes@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-api": "pkg:maven/org.apache.dubbo/dubbo-metadata-api@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-definition-protobuf": "pkg:maven/org.apache.dubbo/dubbo-metadata-definition-protobuf@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-nacos": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-nacos@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-redis": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-redis@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-zookeeper@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metrics-api": "pkg:maven/org.apache.dubbo/dubbo-metrics-api@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metrics-prometheus": "pkg:maven/org.apache.dubbo/dubbo-metrics-prometheus@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-monitor-api": "pkg:maven/org.apache.dubbo/dubbo-monitor-api@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-monitor-default": "pkg:maven/org.apache.dubbo/dubbo-monitor-default@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-qos": "pkg:maven/org.apache.dubbo/dubbo-qos@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-reactive": "pkg:maven/org.apache.dubbo/dubbo-reactive@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-api": "pkg:maven/org.apache.dubbo/dubbo-registry-api@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-multicast": "pkg:maven/org.apache.dubbo/dubbo-registry-multicast@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-multiple": "pkg:maven/org.apache.dubbo/dubbo-registry-multiple@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-nacos": "pkg:maven/org.apache.dubbo/dubbo-registry-nacos@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-registry-zookeeper@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-api": "pkg:maven/org.apache.dubbo/dubbo-remoting-api@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-http": "pkg:maven/org.apache.dubbo/dubbo-remoting-http@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-netty": "pkg:maven/org.apache.dubbo/dubbo-remoting-netty@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-netty4": "pkg:maven/org.apache.dubbo/dubbo-remoting-netty4@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-remoting-zookeeper@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-zookeeper-curator5": "pkg:maven/org.apache.dubbo/dubbo-remoting-zookeeper-curator5@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-api": "pkg:maven/org.apache.dubbo/dubbo-rpc-api@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-dubbo": "pkg:maven/org.apache.dubbo/dubbo-rpc-dubbo@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-grpc": "pkg:maven/org.apache.dubbo/dubbo-rpc-grpc@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-injvm": "pkg:maven/org.apache.dubbo/dubbo-rpc-injvm@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-rest": "pkg:maven/org.apache.dubbo/dubbo-rpc-rest@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-triple": "pkg:maven/org.apache.dubbo/dubbo-rpc-triple@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-api": "pkg:maven/org.apache.dubbo/dubbo-serialization-api@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-fastjson2": "pkg:maven/org.apache.dubbo/dubbo-serialization-fastjson2@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-hessian2": "pkg:maven/org.apache.dubbo/dubbo-serialization-hessian2@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-jdk": "pkg:maven/org.apache.dubbo/dubbo-serialization-jdk@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-xds": "pkg:maven/org.apache.dubbo/dubbo-xds@3.1.4",
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
// "/packages/dubbo-3.1.4.jar": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
"/packages/elasticsearch-8.10.2.jar": "pkg:maven/org.elasticsearch/elasticsearch@8.10.2",
"/packages/elasticsearch-rest-client-sniffer-7.17.11.jar": "pkg:maven/org.elasticsearch.client/elasticsearch-rest-client-sniffer@7.17.11",
"/packages/example-java-app-gradle-0.1.0.ear": "pkg:maven/example-java-app-gradle/example-java-app-gradle@0.1.0",
"/packages/geode-core-1.14.3.jar": "pkg:maven/org.apache.geode/geode-core@1.14.3",
"/packages/github-api-1.118.jar": "pkg:maven/org.kohsuke/github-api@1.118",
"/packages/google-oauth-client-1.25.0.jar": "pkg:maven/com.google.oauth-client/google-oauth-client@1.25.0",
"/packages/graphql-java-20.0.jar:com.google.guava:guava": "pkg:maven/com.google.guava/guava@31.0.1-jre",
"/packages/graphql-java-20.0.jar:org.antlr:antlr4-runtime": "pkg:maven/org.antlr/antlr4-runtime@4.9.3",
"/packages/graphql-java-20.0.jar": "pkg:maven/com.graphql-java/graphql-java@20.0",
"/packages/guava-29.0-jre.jar": "pkg:maven/com.google.guava/guava@29.0-jre",
"/packages/hadoop-common-3.3.2.jar": "pkg:maven/org.apache.hadoop/hadoop-common@3.3.2",
"/packages/hazelcast-5.2.4.jar:com.fasterxml.jackson.core:jackson-core": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.2",
"/packages/hazelcast-5.2.4.jar:com.fasterxml.jackson.jr:jackson-jr-annotation-support": "pkg:maven/com.fasterxml.jackson.jr/jackson-jr-annotation-support@2.15.2",
"/packages/hazelcast-5.2.4.jar:com.fasterxml.jackson.jr:jackson-jr-objects": "pkg:maven/com.fasterxml.jackson.jr/jackson-jr-objects@2.15.2",
"/packages/hazelcast-5.2.4.jar:com.github.erosb:everit-json-schema": "pkg:maven/com.github.erosb/everit-json-schema@1.14.2",
"/packages/hazelcast-5.2.4.jar:com.zaxxer:HikariCP": "pkg:maven/com.zaxxer/HikariCP@4.0.3",
"/packages/hazelcast-5.2.4.jar:io.github.classgraph:classgraph": "pkg:maven/io.github.classgraph/classgraph@4.8.149",
"/packages/hazelcast-5.2.4.jar:org.json:json": "pkg:maven/org.json/json@20230227",
"/packages/hazelcast-5.2.4.jar:org.snakeyaml:snakeyaml-engine": "pkg:maven/org.snakeyaml/snakeyaml-engine@2.3",
"/packages/hazelcast-5.2.4.jar": "pkg:maven/com.hazelcast/hazelcast@5.2.4",
"/packages/hibernate-validator-6.1.3.Final.jar": "pkg:maven/org.hibernate.validator/hibernate-validator@6.1.3.Final",
"/packages/http2-common-11.0.16.jar": "pkg:maven/org.eclipse.jetty.http2/http2-common@11.0.16",
"/packages/hudson.war:WEB-INF/hudson-cli.jar:args4j:args4j": "pkg:maven/args4j/args4j@2.0.16",
"/packages/hudson.war:WEB-INF/hudson-cli.jar:org.jvnet:animal-sniffer-annotation": "pkg:maven/org.jvnet/animal-sniffer-annotation@1.0",
"/packages/hudson.war:WEB-INF/hudson-cli.jar:org.jvnet.hudson.main:remoting": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
"/packages/hudson.war:WEB-INF/hudson-cli.jar:org.jvnet.localizer:localizer": "pkg:maven/org.jvnet.localizer/localizer@1.10",
// "/packages/hudson.war:WEB-INF/hudson-cli.jar": "pkg:maven/org.jvnet.hudson.main/hudson-cli@1.390",
"/packages/hudson.war:WEB-INF/lib/access-modifier-annotation-1.0.jar": "pkg:maven/org.kohsuke/access-modifier-annotation@1.0",
"/packages/hudson.war:WEB-INF/lib/acegi-security-1.0.5.jar": "pkg:maven/org.acegisecurity/acegi-security@1.0.5",
"/packages/hudson.war:WEB-INF/lib/activation-1.1.1-hudson-1.jar": "pkg:maven/org.jvnet.hudson/activation@1.1.1-hudson-1",
"/packages/hudson.war:WEB-INF/lib/akuma-1.2.jar": "pkg:maven/com.sun.akuma/akuma@1.2",
"/packages/hudson.war:WEB-INF/lib/annotation-indexer-1.2.jar": "pkg:maven/org.jvnet.hudson/annotation-indexer@1.2",
"/packages/hudson.war:WEB-INF/lib/ant-1.8.0.jar": "pkg:maven/org.apache.ant/ant@1.8.0",
"/packages/hudson.war:WEB-INF/lib/ant-launcher-1.8.0.jar": "pkg:maven/org.apache.ant/ant-launcher@1.8.0",
"/packages/hudson.war:WEB-INF/lib/antlr-2.7.6.jar": "pkg:maven/antlr/antlr@2.7.6",
"/packages/hudson.war:WEB-INF/lib/aopalliance-1.0.jar": "pkg:maven/aopalliance/aopalliance@1.0",
"/packages/hudson.war:WEB-INF/lib/args4j-2.0.16.jar": "pkg:maven/args4j/args4j@2.0.16",
// "/packages/hudson.war:WEB-INF/lib/asm-2.2.3.jar": "pkg:maven/asm/asm@2.2.3",
// "/packages/hudson.war:WEB-INF/lib/asm-commons-2.2.3.jar": "pkg:maven/asm/asm-commons@2.2.3",
// "/packages/hudson.war:WEB-INF/lib/asm-tree-2.2.3.jar": "pkg:maven/asm/asm-tree@2.2.3",
"/packages/hudson.war:WEB-INF/lib/avalon-framework-4.1.3.jar": "pkg:maven/avalon-framework/avalon-framework@4.1.3",
"/packages/hudson.war:WEB-INF/lib/bridge-method-annotation-1.2.jar": "pkg:maven/com.infradna.tool/bridge-method-annotation@1.2",
"/packages/hudson.war:WEB-INF/lib/cli-1.390.jar": "pkg:maven/org.jvnet.hudson.main/cli@1.390",
"/packages/hudson.war:WEB-INF/lib/commons-beanutils-1.8.0.jar": "pkg:maven/commons-beanutils/commons-beanutils@1.8.0",
"/packages/hudson.war:WEB-INF/lib/commons-codec-1.4.jar": "pkg:maven/commons-codec/commons-codec@1.4",
"/packages/hudson.war:WEB-INF/lib/commons-collections-3.2.jar": "pkg:maven/commons-collections/commons-collections@3.2",
"/packages/hudson.war:WEB-INF/lib/commons-digester-1.7.jar": "pkg:maven/commons-digester/commons-digester@1.7",
"/packages/hudson.war:WEB-INF/lib/commons-discovery-0.4.jar": "pkg:maven/commons-discovery/commons-discovery@0.4",
"/packages/hudson.war:WEB-INF/lib/commons-fileupload-1.2.1.jar": "pkg:maven/commons-fileupload/commons-fileupload@1.2.1",
"/packages/hudson.war:WEB-INF/lib/commons-io-1.4.jar": "pkg:maven/commons-io/commons-io@1.4",
"/packages/hudson.war:WEB-INF/lib/commons-jelly-1.1-hudson-20100305.jar": "pkg:maven/org.jvnet.hudson/commons-jelly@1.1-hudson-20100305",
"/packages/hudson.war:WEB-INF/lib/commons-jelly-tags-define-1.0.1-hudson-20071021.jar": "pkg:maven/org.jvnet.hudson/commons-jelly-tags-define@1.0.1-hudson-20071021",
"/packages/hudson.war:WEB-INF/lib/commons-jelly-tags-fmt-1.0.jar": "pkg:maven/commons-jelly/commons-jelly-tags-fmt@1.0",
"/packages/hudson.war:WEB-INF/lib/commons-jelly-tags-xml-1.1.jar": "pkg:maven/commons-jelly/commons-jelly-tags-xml@1.1",
"/packages/hudson.war:WEB-INF/lib/commons-jexl-1.1-hudson-20090508.jar": "pkg:maven/org.jvnet.hudson/commons-jexl@1.1-hudson-20090508",
"/packages/hudson.war:WEB-INF/lib/commons-lang-2.4.jar": "pkg:maven/commons-lang/commons-lang@2.4",
"/packages/hudson.war:WEB-INF/lib/commons-logging-1.1.jar": "pkg:maven/commons-logging/commons-logging@1.1",
"/packages/hudson.war:WEB-INF/lib/commons-pool-1.3.jar": "pkg:maven/commons-pool/commons-pool@1.3",
"/packages/hudson.war:WEB-INF/lib/crypto-util-1.0.jar": "pkg:maven/org.jvnet.hudson/crypto-util@1.0",
// "/packages/hudson.war:WEB-INF/lib/dom4j-1.6.1-hudson-3.jar": "pkg:maven/org.jvnet.hudson.dom4j/dom4j@1.6.1-hudson-3",
"/packages/hudson.war:WEB-INF/lib/embedded_su4j-1.1.jar": "pkg:maven/com.sun.solaris/embedded_su4j@1.1",
"/packages/hudson.war:WEB-INF/lib/ezmorph-1.0.3.jar": "pkg:maven/net.sf.ezmorph/ezmorph@1.0.3",
"/packages/hudson.war:WEB-INF/lib/graph-layouter-1.0.jar": "pkg:maven/org.kohsuke/graph-layouter@1.0",
"/packages/hudson.war:WEB-INF/lib/groovy-all-1.6.0.jar": "pkg:maven/org.codehaus.groovy/groovy-all@1.6.0",
"/packages/hudson.war:WEB-INF/lib/guava-r06.jar": "pkg:maven/com.google.guava/guava@r06",
"/packages/hudson.war:WEB-INF/lib/hudson-core-1.390.jar": "pkg:maven/org.jvnet.hudson.main/hudson-core@1.390",
"/packages/hudson.war:WEB-INF/lib/j-interop-2.0.5.jar": "pkg:maven/j-interop/j-interop@2.0.5",
"/packages/hudson.war:WEB-INF/lib/j-interopdeps-2.0.5.jar": "pkg:maven/j-interopdeps/j-interopdeps@2.0.5",
"/packages/hudson.war:WEB-INF/lib/jaxen-1.1-beta-11.jar": "pkg:maven/org.jaxen/jaxen@1.1-beta-11",
"/packages/hudson.war:WEB-INF/lib/jcaptcha-all-1.0-RC6.jar": "pkg:maven/jcaptcha-all/jcaptcha-all@1.0-RC6",
"/packages/hudson.war:WEB-INF/lib/jcifs-1.3.14-kohsuke-1.jar": "pkg:maven/org.samba.jcifs/jcifs@1.3.14-kohsuke-1",
"/packages/hudson.war:WEB-INF/lib/jcommon-1.0.12.jar": "pkg:maven/jfree/jcommon@1.0.12",
"/packages/hudson.war:WEB-INF/lib/jfreechart-1.0.9.jar": "pkg:maven/jfreechart/jfreechart@1.0.9",
"/packages/hudson.war:WEB-INF/lib/jinterop-proxy-1.1.jar": "pkg:maven/org.kohsuke.jinterop/jinterop-proxy@1.1",
"/packages/hudson.war:WEB-INF/lib/jinterop-wmi-1.0.jar": "pkg:maven/org.jvnet.hudson/jinterop-wmi@1.0",
"/packages/hudson.war:WEB-INF/lib/jline-0.9.94.jar": "pkg:maven/jline/jline@0.9.94",
"/packages/hudson.war:WEB-INF/lib/jmdns-3.1.6-hudson-2.jar": "pkg:maven/com.strangeberry.jmdns.tools.Main/jmdns@3.1.6-hudson-2",
"/packages/hudson.war:WEB-INF/lib/jna-3.2.4.jar": "pkg:maven/com.sun.jna/jna@3.2.4",
"/packages/hudson.war:WEB-INF/lib/jna-posix-1.0.3.jar": "pkg:maven/org.jruby.ext.posix/jna-posix@1.0.3",
"/packages/hudson.war:WEB-INF/lib/json-lib-2.1-rev6.jar": "pkg:maven/json-lib/json-lib@2.1-rev6",
"/packages/hudson.war:WEB-INF/lib/jstl-1.1.0.jar": "pkg:maven/com.sun/jstl@1.1.0",
"/packages/hudson.war:WEB-INF/lib/jtidy-4aug2000r7-dev-hudson-1.jar": "pkg:maven/jtidy/jtidy@4aug2000r7-dev-hudson-1",
"/packages/hudson.war:WEB-INF/lib/libpam4j-1.2.jar": "pkg:maven/org.jvnet.libpam4j/libpam4j@1.2",
"/packages/hudson.war:WEB-INF/lib/libzfs-0.5.jar": "pkg:maven/org.jvnet.libzfs/libzfs@0.5",
"/packages/hudson.war:WEB-INF/lib/localizer-1.10.jar": "pkg:maven/org.jvnet.localizer/localizer@1.10",
"/packages/hudson.war:WEB-INF/lib/log4j-1.2.9.jar": "pkg:maven/log4j/log4j@1.2.9",
"/packages/hudson.war:WEB-INF/lib/logkit-1.0.1.jar": "pkg:maven/logkit/logkit@1.0.1",
"/packages/hudson.war:WEB-INF/lib/mail-1.4.jar": "pkg:maven/com.sun/mail@1.4",
"/packages/hudson.war:WEB-INF/lib/memory-monitor-1.3.jar": "pkg:maven/org.jvnet.hudson/memory-monitor@1.3",
"/packages/hudson.war:WEB-INF/lib/oro-2.0.8.jar": "pkg:maven/org.apache.oro/oro@2.0.8",
"/packages/hudson.war:WEB-INF/lib/remoting-1.390.jar:args4j:args4j": "pkg:maven/args4j/args4j@2.0.16",
"/packages/hudson.war:WEB-INF/lib/remoting-1.390.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
"/packages/hudson.war:WEB-INF/lib/robust-http-client-1.1.jar": "pkg:maven/org.jvnet.robust-http-client/robust-http-client@1.1",
"/packages/hudson.war:WEB-INF/lib/sezpoz-1.7.jar": "pkg:maven/net.java.sezpoz/sezpoz@1.7",
"/packages/hudson.war:WEB-INF/lib/spring-aop-2.5.jar": "pkg:maven/org.springframework/spring-aop@2.5",
"/packages/hudson.war:WEB-INF/lib/spring-beans-2.5.jar": "pkg:maven/org.springframework/spring-beans@2.5",
"/packages/hudson.war:WEB-INF/lib/spring-context-2.5.jar": "pkg:maven/org.springframework/spring-context@2.5",
"/packages/hudson.war:WEB-INF/lib/spring-core-2.5.jar": "pkg:maven/org.springframework/spring-core@2.5",
"/packages/hudson.war:WEB-INF/lib/spring-dao-1.2.9.jar": "pkg:maven/org.springframework/spring-dao@1.2.9",
"/packages/hudson.war:WEB-INF/lib/spring-jdbc-1.2.9.jar": "pkg:maven/org.springframework/spring-jdbc@1.2.9",
"/packages/hudson.war:WEB-INF/lib/spring-web-2.5.jar": "pkg:maven/org.springframework/spring-web@2.5",
"/packages/hudson.war:WEB-INF/lib/stapler-1.155.jar": "pkg:maven/org.kohsuke.stapler/stapler@1.155",
"/packages/hudson.war:WEB-INF/lib/stapler-adjunct-timeline-1.2.jar": "pkg:maven/org.kohsuke.stapler/stapler-adjunct-timeline@1.2",
"/packages/hudson.war:WEB-INF/lib/stapler-jelly-1.155.jar": "pkg:maven/org.kohsuke.stapler/stapler-jelly@1.155",
"/packages/hudson.war:WEB-INF/lib/stax-api-1.0.1.jar": "pkg:maven/stax-api/stax-api@1.0.1",
"/packages/hudson.war:WEB-INF/lib/task-reactor-1.2.jar": "pkg:maven/org.jvnet.hudson/task-reactor@1.2",
"/packages/hudson.war:WEB-INF/lib/tiger-types-1.3.jar": "pkg:maven/org.jvnet/tiger-types@1.3",
"/packages/hudson.war:WEB-INF/lib/trilead-putty-extension-1.0.jar": "pkg:maven/org.kohsuke/trilead-putty-extension@1.0",
"/packages/hudson.war:WEB-INF/lib/trilead-ssh2-build212-hudson-5.jar": "pkg:maven/org.jvnet.hudson/trilead-ssh2@build212-hudson-5",
"/packages/hudson.war:WEB-INF/lib/txw2-20070624.jar": "pkg:maven/txw2/txw2@20070624",
"/packages/hudson.war:WEB-INF/lib/windows-remote-command-1.0.jar": "pkg:maven/org.jvnet.hudson/windows-remote-command@1.0",
"/packages/hudson.war:WEB-INF/lib/winp-1.14.jar": "pkg:maven/org.jvnet.winp/winp@1.14",
"/packages/hudson.war:WEB-INF/lib/wstx-asl-3.2.7.jar": "pkg:maven/wstx-asl/wstx-asl@3.2.7",
// "/packages/hudson.war:WEB-INF/lib/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3_min/xpp3_min@1.1.4c",
// "/packages/hudson.war:WEB-INF/lib/xpp3-1.1.4c.jar": "pkg:maven/xpp3/xpp3@1.1.4c",
"/packages/hudson.war:WEB-INF/lib/xstream-1.3.1-hudson-8.jar": "pkg:maven/org.jvnet.hudson/xstream@1.3.1-hudson-8",
"/packages/hudson.war:WEB-INF/plugins/cvs.hpi": "pkg:maven/org.jvnet.hudson.plugins/cvs@1.2",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/avalon-framework-4.1.3.jar": "pkg:maven/avalon-framework/avalon-framework@4.1.3",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/classworlds-1.1.jar": "pkg:maven/org.codehaus.classworlds/classworlds@1.1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/commons-codec-1.4.jar": "pkg:maven/commons-codec/commons-codec@1.4",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/commons-httpclient-3.1-rc1.jar": "pkg:maven/commons-httpclient/commons-httpclient@3.1-rc1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/commons-logging-1.1.jar": "pkg:maven/commons-logging/commons-logging@1.1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/doxia-sink-api-1.0-alpha-10.jar": "pkg:maven/org.apache.maven.doxia/doxia-sink-api@1.0-alpha-10",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/jsch-0.1.27.jar": "pkg:maven/jsch/jsch@0.1.27",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/log4j-1.2.9.jar": "pkg:maven/log4j/log4j@1.2.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/logkit-1.0.1.jar": "pkg:maven/logkit/logkit@1.0.1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-agent-1.390.jar": "pkg:maven/org.jvnet.hudson.main/maven-agent@1.390",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-artifact-2.0.9.jar": "pkg:maven/org.apache.maven/maven-artifact@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-artifact-manager-2.0.9.jar": "pkg:maven/org.apache.maven/maven-artifact-manager@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-core-2.0.9.jar": "pkg:maven/org.apache.maven/maven-core@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-embedder-2.0.4-hudson-1.jar": "pkg:maven/org.jvnet.hudson/maven-embedder@2.0.4-hudson-1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-embedder-2.0.4.jar": "pkg:maven/org.apache.maven/maven-embedder@2.0.4",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-error-diagnostics-2.0.9.jar": "pkg:maven/org.apache.maven/maven-error-diagnostics@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-interceptor-1.390.jar": "pkg:maven/org.jvnet.hudson.main/maven-interceptor@1.390",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-model-2.0.9.jar": "pkg:maven/org.apache.maven/maven-model@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-monitor-2.0.9.jar": "pkg:maven/org.apache.maven/maven-monitor@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-plugin-api-2.0.9.jar": "pkg:maven/org.apache.maven/maven-plugin-api@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-plugin-descriptor-2.0.9.jar": "pkg:maven/org.apache.maven/maven-plugin-descriptor@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-plugin-parameter-documenter-2.0.9.jar": "pkg:maven/org.apache.maven/maven-plugin-parameter-documenter@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-plugin-registry-2.0.9.jar": "pkg:maven/org.apache.maven/maven-plugin-registry@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-profile-2.0.9.jar": "pkg:maven/org.apache.maven/maven-profile@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-project-2.0.9.jar": "pkg:maven/org.apache.maven/maven-project@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-reporting-api-2.0.9.jar": "pkg:maven/org.apache.maven.reporting/maven-reporting-api@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-repository-metadata-2.0.9.jar": "pkg:maven/org.apache.maven/maven-repository-metadata@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-settings-2.0.9.jar": "pkg:maven/org.apache.maven/maven-settings@2.0.9",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven2.1-interceptor-1.2.jar": "pkg:maven/org.jvnet.hudson/maven2.1-interceptor@1.2",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/plexus-container-default-1.0-alpha-9-stable-1.jar": "pkg:maven/org.codehaus.plexus/plexus-container-default@1.0-alpha-9-stable-1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/plexus-interactivity-api-1.0-alpha-4.jar": "pkg:maven/org.codehaus.plexus/plexus-interactivity-api@1.0-alpha-4",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/plexus-utils-1.5.1.jar": "pkg:maven/org.codehaus.plexus/plexus-utils@1.5.1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/slide-webdavlib-2.1.jar": "pkg:maven/slide-webdavlib/slide-webdavlib@2.1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-file-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-file@1.0-beta-2",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-http-lightweight-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-http-lightweight@1.0-beta-2",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-http-shared-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-http-shared@1.0-beta-2",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-provider-api-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-provider-api@1.0-beta-2",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-ssh-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-ssh@1.0-beta-2",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-ssh-common-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-ssh-common@1.0-beta-2",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-ssh-external-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-ssh-external@1.0-beta-2",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-webdav-1.0-beta-2-hudson-1.jar": "pkg:maven/org.jvnet.hudson/wagon-webdav@1.0-beta-2-hudson-1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/xml-im-exporter-1.1.jar": "pkg:maven/xml-im-exporter/xml-im-exporter@1.1",
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi": "pkg:maven/org.jvnet.hudson.main/maven-plugin@1.390",
"/packages/hudson.war:WEB-INF/plugins/ssh-slaves.hpi": "pkg:maven/org.jvnet.hudson.plugins/ssh-slaves@0.14",
"/packages/hudson.war:WEB-INF/plugins/subversion.hpi:WEB-INF/lib/svnkit-1.3.4-hudson-2.jar": "pkg:maven/svnkit/svnkit@1.3.4-hudson-2",
"/packages/hudson.war:WEB-INF/plugins/subversion.hpi": "pkg:maven/org.jvnet.hudson.plugins/subversion@1.20",
"/packages/hudson.war:WEB-INF/remoting.jar:args4j:args4j": "pkg:maven/args4j/args4j@2.0.16",
"/packages/hudson.war:WEB-INF/remoting.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
"/packages/hudson.war:WEB-INF/slave.jar:args4j:args4j": "pkg:maven/args4j/args4j@2.0.16",
"/packages/hudson.war:WEB-INF/slave.jar:org.jvnet.hudson.main:remoting": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
// "/packages/hudson.war:WEB-INF/slave.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
"/packages/hudson.war:winstone.jar": "pkg:maven/org.jvnet.hudson.winstone/winstone@0.9.10-hudson-24",
"/packages/hudson.war": "pkg:maven/org.jvnet.hudson.main/hudson-war@1.390",
"/packages/infinispan-core-11.0.4.Final.jar": "pkg:maven/org.infinispan/infinispan-core@11.0.4.Final",
"/packages/jeecg-boot-common-3.6.0.jar": "pkg:maven/org.jeecgframework.boot/jeecg-boot-common@3.6.0",
"/packages/jetty-client-9.4.31.v20200723.jar": "pkg:maven/org.eclipse.jetty/jetty-client@9.4.31.v20200723",
"/packages/jetty-server-12.0.0.alpha3.jar": "pkg:maven/org.eclipse.jetty/jetty-server@12.0.0.alpha3",
"/packages/jetty-setuid-java-1.0.4.jar": "pkg:maven/org.eclipse.jetty.toolchain.setuid/jetty-setuid-java@1.0.4",
"/packages/jmdns-3.4.1.jar": "pkg:maven/javax.jmdns/jmdns@3.4.1",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/jopenssl.jar:rubygems:jruby-openssl": "pkg:maven/rubygems/jruby-openssl@0.9.21",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/org/bouncycastle/bcpkix-jdk15on/1.56/bcpkix-jdk15on-1.56.jar": "pkg:maven/org.bouncycastle/bcpkix-jdk15on@1.56",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/org/bouncycastle/bcprov-jdk15on/1.56/bcprov-jdk15on-1.56.jar": "pkg:maven/org.bouncycastle/bcprov-jdk15on@1.56",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/org/yaml/snakeyaml/1.18/snakeyaml-1.18.jar": "pkg:maven/org.yaml/snakeyaml@1.18",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/readline.jar:jline:jline": "pkg:maven/jline/jline@2.11",
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/readline.jar:rubygems:jruby-readline": "pkg:maven/rubygems/jruby-readline@1.2.0",
"/packages/jruby-stdlib-9.1.15.0.jar": "pkg:maven/org.jruby/jruby-stdlib@9.1.15.0",
"/packages/jsch-0.1.55.jar": "pkg:maven/com.jcraft/jsch@0.1.55",
"/packages/junit-4.13.1.jar": "pkg:maven/junit/junit@4.13.1",
// "/packages/kafka_2.13-3.2.2.jar": "pkg:maven/org.apache.kafka/kafka_2.13@3.2.2",
"/packages/keycloak-core-22.0.2.jar": "pkg:maven/org.keycloak/keycloak-core@22.0.2",
"/packages/log4j-1.2.16.jar": "pkg:maven/log4j/log4j@1.2.16",
"/packages/log4j-core-2.17.0.jar": "pkg:maven/org.apache.logging.log4j/log4j-core@2.17.0",
"/packages/log4j-over-slf4j-1.7.36.jar": "pkg:maven/org.slf4j/log4j-over-slf4j@1.7.36",
"/packages/manager-pojo-1.8.0.jar": "pkg:maven/org.apache.inlong/manager-pojo@1.8.0",
"/packages/maven-shared-utils-3.2.1.jar": "pkg:maven/org.apache.maven.shared/maven-shared-utils@3.2.1",
"/packages/mesos-1.7.1.jar": "pkg:maven/org.apache.mesos/mesos@1.7.1",
"/packages/minio-8.3.8.jar": "pkg:maven/io.minio/minio@8.3.8",
"/packages/ms-mcms-5.3.1.jar": "pkg:maven/net.mingsoft/ms-mcms@5.3.1",
"/packages/my-app-1.jar:com.fasterxml:classmate": "pkg:maven/com.fasterxml/classmate@1.5.1",
"/packages/my-app-1.jar:com.fasterxml.jackson.core:jackson-annotations": "pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.13.2",
"/packages/my-app-1.jar:com.fasterxml.jackson.core:jackson-core": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.13.2",
"/packages/my-app-1.jar:com.fasterxml.jackson.core:jackson-databind": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.0",
"/packages/my-app-1.jar:com.google.errorprone:error_prone_annotations": "pkg:maven/com.google.errorprone/error_prone_annotations@2.0.18",
"/packages/my-app-1.jar:com.google.guava:guava": "pkg:maven/com.google.guava/guava@23.0",
"/packages/my-app-1.jar:com.google.j2objc:j2objc-annotations": "pkg:maven/com.google.j2objc/j2objc-annotations@1.1",
"/packages/my-app-1.jar:com.hazelcast:hazelcast-kubernetes": "pkg:maven/com.hazelcast/hazelcast-kubernetes@1.5.4",
"/packages/my-app-1.jar:com.hierynomus:asn-one": "pkg:maven/com.hierynomus/asn-one@0.5.0",
"/packages/my-app-1.jar:com.typesafe.netty:netty-reactive-streams": "pkg:maven/com.typesafe.netty/netty-reactive-streams@2.0.5",
"/packages/my-app-1.jar:commons-beanutils:commons-beanutils": "pkg:maven/commons-beanutils/commons-beanutils@1.9.2",
"/packages/my-app-1.jar:commons-collections:commons-collections": "pkg:maven/commons-collections/commons-collections@3.2.2",
"/packages/my-app-1.jar:commons-digester:commons-digester": "pkg:maven/commons-digester/commons-digester@1.8.1",
"/packages/my-app-1.jar:commons-io:commons-io": "pkg:maven/commons-io/commons-io@2.8.0",
"/packages/my-app-1.jar:commons-logging:commons-logging": "pkg:maven/commons-logging/commons-logging@1.2",
"/packages/my-app-1.jar:commons-validator:commons-validator": "pkg:maven/commons-validator/commons-validator@1.5.1",
"/packages/my-app-1.jar:io.netty:netty-buffer": "pkg:maven/io.netty/netty-buffer@4.1.52.Final",
"/packages/my-app-1.jar:io.netty:netty-codec-dns": "pkg:maven/io.netty/netty-codec-dns@4.1.63.Final",
"/packages/my-app-1.jar:io.netty:netty-codec-http": "pkg:maven/io.netty/netty-codec-http@4.1.63.Final",
"/packages/my-app-1.jar:io.netty:netty-codec-socks": "pkg:maven/io.netty/netty-codec-socks@4.1.63.Final",
"/packages/my-app-1.jar:io.netty:netty-codec": "pkg:maven/io.netty/netty-codec@4.1.52.Final",
"/packages/my-app-1.jar:io.netty:netty-common": "pkg:maven/io.netty/netty-common@4.1.52.Final",
"/packages/my-app-1.jar:io.netty:netty-handler-proxy": "pkg:maven/io.netty/netty-handler-proxy@4.1.63.Final",
"/packages/my-app-1.jar:io.netty:netty-handler": "pkg:maven/io.netty/netty-handler@4.1.52.Final",
"/packages/my-app-1.jar:io.netty:netty-resolver-dns-native-macos": "pkg:maven/io.netty/netty-resolver-dns-native-macos@4.1.63.Final",
"/packages/my-app-1.jar:io.netty:netty-resolver-dns": "pkg:maven/io.netty/netty-resolver-dns@4.1.63.Final",
"/packages/my-app-1.jar:io.netty:netty-resolver": "pkg:maven/io.netty/netty-resolver@4.1.52.Final",
"/packages/my-app-1.jar:io.netty:netty-transport-native-epoll": "pkg:maven/io.netty/netty-transport-native-epoll@4.1.63.Final",
"/packages/my-app-1.jar:io.netty:netty-transport-native-unix-common": "pkg:maven/io.netty/netty-transport-native-unix-common@4.1.63.Final",
"/packages/my-app-1.jar:io.netty:netty-transport": "pkg:maven/io.netty/netty-transport@4.1.52.Final",
"/packages/my-app-1.jar:io.prometheus:simpleclient_common": "pkg:maven/io.prometheus/simpleclient_common@0.9.0",
"/packages/my-app-1.jar:io.prometheus:simpleclient": "pkg:maven/io.prometheus/simpleclient@0.9.0",
"/packages/my-app-1.jar:io.vavr:vavr-match": "pkg:maven/io.vavr/vavr-match@0.10.2",
"/packages/my-app-1.jar:io.vavr:vavr": "pkg:maven/io.vavr/vavr@0.10.2",
"/packages/my-app-1.jar:jakarta.validation:jakarta.validation-api": "pkg:maven/jakarta.validation/jakarta.validation-api@2.0.2",
"/packages/my-app-1.jar:javax.servlet:javax.servlet-api": "pkg:maven/javax.servlet/javax.servlet-api@3.1.0",
"/packages/my-app-1.jar:org.apache.activemq.protobuf:activemq-protobuf": "pkg:maven/org.apache.activemq.protobuf/activemq-protobuf@1.1",
"/packages/my-app-1.jar:org.apache.commons:commons-compress": "pkg:maven/org.apache.commons/commons-compress@1.21",
"/packages/my-app-1.jar:org.apache.commons:commons-lang3": "pkg:maven/org.apache.commons/commons-lang3@3.10",
"/packages/my-app-1.jar:org.apache.maven.shared:maven-shared-utils": "pkg:maven/org.apache.maven.shared/maven-shared-utils@3.3.4",
"/packages/my-app-1.jar:org.codehaus.mojo:animal-sniffer-annotations": "pkg:maven/org.codehaus.mojo/animal-sniffer-annotations@1.14",
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-client": "pkg:maven/org.eclipse.jetty/jetty-client@9.4.43.v20210629",
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-http": "pkg:maven/org.eclipse.jetty/jetty-http@9.4.43.v20210629",
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-io": "pkg:maven/org.eclipse.jetty/jetty-io@9.4.43.v20210629",
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-server": "pkg:maven/org.eclipse.jetty/jetty-server@9.1.0.M0",
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-util": "pkg:maven/org.eclipse.jetty/jetty-util@9.4.43.v20210629",
"/packages/my-app-1.jar:org.eclipse.jetty.http2:http2-common": "pkg:maven/org.eclipse.jetty.http2/http2-common@9.4.43.v20210629",
"/packages/my-app-1.jar:org.eclipse.jetty.http2:http2-hpack": "pkg:maven/org.eclipse.jetty.http2/http2-hpack@9.4.43.v20210629",
"/packages/my-app-1.jar:org.eclipse.jetty.toolchain.setuid:jetty-setuid-java": "pkg:maven/org.eclipse.jetty.toolchain.setuid/jetty-setuid-java@1.0.4",
"/packages/my-app-1.jar:org.everit.json:org.everit.json.schema": "pkg:maven/org.everit.json/org.everit.json.schema@1.5.1",
"/packages/my-app-1.jar:org.hibernate.validator:hibernate-validator": "pkg:maven/org.hibernate.validator/hibernate-validator@6.2.4.Final",
"/packages/my-app-1.jar:org.jboss.logging:jboss-logging": "pkg:maven/org.jboss.logging/jboss-logging@3.4.1.Final",
"/packages/my-app-1.jar:org.jctools:jctools-core": "pkg:maven/org.jctools/jctools-core@3.1.0",
"/packages/my-app-1.jar:org.jetbrains:annotations": "pkg:maven/org.jetbrains/annotations@13.0",
"/packages/my-app-1.jar:org.json:json": "pkg:maven/org.json/json@20160810",
"/packages/my-app-1.jar:org.kohsuke:github-api": "pkg:maven/org.kohsuke/github-api@1.301",
"/packages/my-app-1.jar:org.slf4j:log4j-over-slf4j": "pkg:maven/org.slf4j/log4j-over-slf4j@1.7.33",
"/packages/my-app-1.jar:org.slf4j:slf4j-api": "pkg:maven/org.slf4j/slf4j-api@1.7.33",
"/packages/my-app-1.jar:org.sonarsource.analyzer-commons:sonar-analyzer-test-commons": "pkg:maven/org.sonarsource.analyzer-commons/sonar-analyzer-test-commons@1.14.1.690",
"/packages/my-app-1.jar:org.sonarsource.php:php-checks": "pkg:maven/org.sonarsource.php/php-checks@3.17.0.7439",
"/packages/my-app-1.jar:org.sonarsource.php:php-frontend": "pkg:maven/org.sonarsource.php/php-frontend@3.17.0.7439",
"/packages/my-app-1.jar:org.sonarsource.python:python-checks": "pkg:maven/org.sonarsource.python/python-checks@3.4.1.8066",
"/packages/my-app-1.jar:org.sonarsource.python:python-frontend": "pkg:maven/org.sonarsource.python/python-frontend@3.4.1.8066",
"/packages/my-app-1.jar:org.sonarsource.sslr:sslr-core": "pkg:maven/org.sonarsource.sslr/sslr-core@1.24.0.633",
"/packages/my-app-1.jar": "pkg:maven/com.mycompany.app/my-app@1",
"/packages/netty-reactive-streams-2.0.6.jar": "pkg:maven/com.typesafe.netty/netty-reactive-streams@2.0.6",
"/packages/nifi-utils-1.12.0.jar": "pkg:maven/org.apache.nifi/nifi-utils@1.12.0",
"/packages/nomad.hpi:WEB-INF/lib/annotations-13.0.jar": "pkg:maven/org.jetbrains/annotations@13.0",
"/packages/nomad.hpi:WEB-INF/lib/gson-2.8.6.jar": "pkg:maven/com.google.code.gson/gson@2.8.6",
"/packages/nomad.hpi:WEB-INF/lib/json-20200518.jar": "pkg:maven/org.json/json@20200518",
"/packages/nomad.hpi:WEB-INF/lib/kotlin-stdlib-1.3.70.jar": "pkg:maven/kotlin-stdlib/kotlin-stdlib@1.3.70",
"/packages/nomad.hpi:WEB-INF/lib/kotlin-stdlib-common-1.3.70.jar": "pkg:maven/kotlin-stdlib-common/kotlin-stdlib-common@1.3.70",
"/packages/nomad.hpi:WEB-INF/lib/nomad.jar": "pkg:maven/org.jenkins-ci.plugins/nomad@0.7.4",
"/packages/nomad.hpi:WEB-INF/lib/okhttp-4.5.0.jar": "pkg:maven/com.squareup.okhttp3/okhttp@4.5.0",
"/packages/nomad.hpi:WEB-INF/lib/okio-2.5.0.jar": "pkg:maven/com.squareup.okio/okio@2.5.0",
"/packages/nomad.hpi": "pkg:maven/org.jenkins-ci.plugins/nomad@0.7.4",
"/packages/openmeetings-util-4.0.9.jar": "pkg:maven/org.apache.openmeetings/openmeetings-util@4.0.9",
"/packages/org.eclipse.ant.core-3.7.0.jar": "pkg:maven/org.eclipse.platform/org.eclipse.ant.core@3.7.0",
"/packages/org.eclipse.osgi-3.18.0.jar": "pkg:maven/org.eclipse.platform/org.eclipse.osgi@3.18.0",
"/packages/org.everit.json.schema-1.5.1.jar": "pkg:maven/org.everit.json/org.everit.json.schema@1.5.1",
"/packages/original-my-app-1.jar:com.fasterxml:classmate": "pkg:maven/com.fasterxml/classmate@1.5.1",
"/packages/original-my-app-1.jar:com.fasterxml.jackson.core:jackson-annotations": "pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.13.2",
"/packages/original-my-app-1.jar:com.fasterxml.jackson.core:jackson-core": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.13.2",
"/packages/original-my-app-1.jar:com.fasterxml.jackson.core:jackson-databind": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.0",
"/packages/original-my-app-1.jar:com.google.errorprone:error_prone_annotations": "pkg:maven/com.google.errorprone/error_prone_annotations@2.0.18",
"/packages/original-my-app-1.jar:com.google.guava:guava": "pkg:maven/com.google.guava/guava@23.0",
"/packages/original-my-app-1.jar:com.google.j2objc:j2objc-annotations": "pkg:maven/com.google.j2objc/j2objc-annotations@1.1",
"/packages/original-my-app-1.jar:com.hazelcast:hazelcast-kubernetes": "pkg:maven/com.hazelcast/hazelcast-kubernetes@1.5.4",
"/packages/original-my-app-1.jar:com.hierynomus:asn-one": "pkg:maven/com.hierynomus/asn-one@0.5.0",
"/packages/original-my-app-1.jar:com.typesafe.netty:netty-reactive-streams": "pkg:maven/com.typesafe.netty/netty-reactive-streams@2.0.5",
"/packages/original-my-app-1.jar:commons-beanutils:commons-beanutils": "pkg:maven/commons-beanutils/commons-beanutils@1.9.2",
"/packages/original-my-app-1.jar:commons-collections:commons-collections": "pkg:maven/commons-collections/commons-collections@3.2.2",
"/packages/original-my-app-1.jar:commons-digester:commons-digester": "pkg:maven/commons-digester/commons-digester@1.8.1",
"/packages/original-my-app-1.jar:commons-io:commons-io": "pkg:maven/commons-io/commons-io@2.8.0",
"/packages/original-my-app-1.jar:commons-logging:commons-logging": "pkg:maven/commons-logging/commons-logging@1.2",
"/packages/original-my-app-1.jar:commons-validator:commons-validator": "pkg:maven/commons-validator/commons-validator@1.5.1",
"/packages/original-my-app-1.jar:io.netty:netty-buffer": "pkg:maven/io.netty/netty-buffer@4.1.52.Final",
"/packages/original-my-app-1.jar:io.netty:netty-codec-dns": "pkg:maven/io.netty/netty-codec-dns@4.1.63.Final",
"/packages/original-my-app-1.jar:io.netty:netty-codec-http": "pkg:maven/io.netty/netty-codec-http@4.1.63.Final",
"/packages/original-my-app-1.jar:io.netty:netty-codec-socks": "pkg:maven/io.netty/netty-codec-socks@4.1.63.Final",
"/packages/original-my-app-1.jar:io.netty:netty-codec": "pkg:maven/io.netty/netty-codec@4.1.52.Final",
"/packages/original-my-app-1.jar:io.netty:netty-common": "pkg:maven/io.netty/netty-common@4.1.52.Final",
"/packages/original-my-app-1.jar:io.netty:netty-handler-proxy": "pkg:maven/io.netty/netty-handler-proxy@4.1.63.Final",
"/packages/original-my-app-1.jar:io.netty:netty-handler": "pkg:maven/io.netty/netty-handler@4.1.52.Final",
"/packages/original-my-app-1.jar:io.netty:netty-resolver-dns-native-macos": "pkg:maven/io.netty/netty-resolver-dns-native-macos@4.1.63.Final",
"/packages/original-my-app-1.jar:io.netty:netty-resolver-dns": "pkg:maven/io.netty/netty-resolver-dns@4.1.63.Final",
"/packages/original-my-app-1.jar:io.netty:netty-resolver": "pkg:maven/io.netty/netty-resolver@4.1.52.Final",
"/packages/original-my-app-1.jar:io.netty:netty-transport-native-epoll": "pkg:maven/io.netty/netty-transport-native-epoll@4.1.63.Final",
"/packages/original-my-app-1.jar:io.netty:netty-transport-native-unix-common": "pkg:maven/io.netty/netty-transport-native-unix-common@4.1.63.Final",
"/packages/original-my-app-1.jar:io.netty:netty-transport": "pkg:maven/io.netty/netty-transport@4.1.52.Final",
"/packages/original-my-app-1.jar:io.prometheus:simpleclient_common": "pkg:maven/io.prometheus/simpleclient_common@0.9.0",
"/packages/original-my-app-1.jar:io.prometheus:simpleclient": "pkg:maven/io.prometheus/simpleclient@0.9.0",
"/packages/original-my-app-1.jar:io.vavr:vavr-match": "pkg:maven/io.vavr/vavr-match@0.10.2",
"/packages/original-my-app-1.jar:io.vavr:vavr": "pkg:maven/io.vavr/vavr@0.10.2",
"/packages/original-my-app-1.jar:jakarta.validation:jakarta.validation-api": "pkg:maven/jakarta.validation/jakarta.validation-api@2.0.2",
"/packages/original-my-app-1.jar:javax.servlet:javax.servlet-api": "pkg:maven/javax.servlet/javax.servlet-api@3.1.0",
"/packages/original-my-app-1.jar:org.apache.activemq.protobuf:activemq-protobuf": "pkg:maven/org.apache.activemq.protobuf/activemq-protobuf@1.1",
"/packages/original-my-app-1.jar:org.apache.commons:commons-compress": "pkg:maven/org.apache.commons/commons-compress@1.21",
"/packages/original-my-app-1.jar:org.apache.commons:commons-lang3": "pkg:maven/org.apache.commons/commons-lang3@3.10",
"/packages/original-my-app-1.jar:org.apache.maven.shared:maven-shared-utils": "pkg:maven/org.apache.maven.shared/maven-shared-utils@3.3.4",
"/packages/original-my-app-1.jar:org.codehaus.mojo:animal-sniffer-annotations": "pkg:maven/org.codehaus.mojo/animal-sniffer-annotations@1.14",
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-client": "pkg:maven/org.eclipse.jetty/jetty-client@9.4.43.v20210629",
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-http": "pkg:maven/org.eclipse.jetty/jetty-http@9.4.43.v20210629",
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-io": "pkg:maven/org.eclipse.jetty/jetty-io@9.4.43.v20210629",
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-server": "pkg:maven/org.eclipse.jetty/jetty-server@9.1.0.M0",
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-util": "pkg:maven/org.eclipse.jetty/jetty-util@9.4.43.v20210629",
"/packages/original-my-app-1.jar:org.eclipse.jetty.http2:http2-common": "pkg:maven/org.eclipse.jetty.http2/http2-common@9.4.43.v20210629",
"/packages/original-my-app-1.jar:org.eclipse.jetty.http2:http2-hpack": "pkg:maven/org.eclipse.jetty.http2/http2-hpack@9.4.43.v20210629",
"/packages/original-my-app-1.jar:org.eclipse.jetty.toolchain.setuid:jetty-setuid-java": "pkg:maven/org.eclipse.jetty.toolchain.setuid/jetty-setuid-java@1.0.4",
"/packages/original-my-app-1.jar:org.everit.json:org.everit.json.schema": "pkg:maven/org.everit.json/org.everit.json.schema@1.5.1",
"/packages/original-my-app-1.jar:org.hibernate.validator:hibernate-validator": "pkg:maven/org.hibernate.validator/hibernate-validator@6.2.4.Final",
"/packages/original-my-app-1.jar:org.jboss.logging:jboss-logging": "pkg:maven/org.jboss.logging/jboss-logging@3.4.1.Final",
"/packages/original-my-app-1.jar:org.jctools:jctools-core": "pkg:maven/org.jctools/jctools-core@3.1.0",
"/packages/original-my-app-1.jar:org.jetbrains:annotations": "pkg:maven/org.jetbrains/annotations@13.0",
"/packages/original-my-app-1.jar:org.json:json": "pkg:maven/org.json/json@20160810",
"/packages/original-my-app-1.jar:org.kohsuke:github-api": "pkg:maven/org.kohsuke/github-api@1.301",
"/packages/original-my-app-1.jar:org.slf4j:log4j-over-slf4j": "pkg:maven/org.slf4j/log4j-over-slf4j@1.7.33",
"/packages/original-my-app-1.jar:org.slf4j:slf4j-api": "pkg:maven/org.slf4j/slf4j-api@1.7.33",
"/packages/original-my-app-1.jar:org.sonarsource.analyzer-commons:sonar-analyzer-test-commons": "pkg:maven/org.sonarsource.analyzer-commons/sonar-analyzer-test-commons@1.14.1.690",
"/packages/original-my-app-1.jar:org.sonarsource.php:php-checks": "pkg:maven/org.sonarsource.php/php-checks@3.17.0.7439",
"/packages/original-my-app-1.jar:org.sonarsource.php:php-frontend": "pkg:maven/org.sonarsource.php/php-frontend@3.17.0.7439",
"/packages/original-my-app-1.jar:org.sonarsource.python:python-checks": "pkg:maven/org.sonarsource.python/python-checks@3.4.1.8066",
"/packages/original-my-app-1.jar:org.sonarsource.python:python-frontend": "pkg:maven/org.sonarsource.python/python-frontend@3.4.1.8066",
"/packages/original-my-app-1.jar:org.sonarsource.sslr:sslr-core": "pkg:maven/org.sonarsource.sslr/sslr-core@1.24.0.633",
"/packages/original-my-app-1.jar": "pkg:maven/com.mycompany.app/my-app@1",
"/packages/php-frontend-3.9.0.6331.jar": "pkg:maven/org.sonarsource.php/php-frontend@3.9.0.6331",
"/packages/postgresql-42.5.0.jar": "pkg:maven/org.postgresql/postgresql@42.5.0",
"/packages/protobuf-java-3.21.6.jar": "pkg:maven/com.google.protobuf/protobuf-java@3.21.6",
"/packages/python-frontend-3.24.0.10784.jar": "pkg:maven/org.sonarsource.python/python-frontend@3.24.0.10784",
"/packages/ratpack-core-1.8.2.jar": "pkg:maven/io.ratpack/ratpack-core@1.8.2",
"/packages/reactor-netty-core-1.0.35.jar": "pkg:maven/io.projectreactor.netty/reactor-netty-core@1.0.35",
"/packages/reactor-netty-http-1.1.9.jar": "pkg:maven/io.projectreactor.netty/reactor-netty-http@1.1.9",
"/packages/reactor-netty-incubator-quic-0.1.3.jar": "pkg:maven/io.projectreactor.netty.incubator/reactor-netty-incubator-quic@0.1.3",
"/packages/resilience4j-prometheus-0.17.0.jar": "pkg:maven/io.github.resilience4j.prometheus/resilience4j-prometheus@0.17.0",
"/packages/shiro-core-1.9.1.jar": "pkg:maven/org.apache.shiro/shiro-core@1.9.1",
"/packages/solr-core-8.8.1.jar": "pkg:maven/org.apache.solr/solr-core@8.8.1",
"/packages/spring-amqp-2.4.17.jar": "pkg:maven/org.springframework.amqp/spring-amqp@2.4.17",
"/packages/spring-analytics-2.0.0.RELEASE.jar": "pkg:maven/org.springframework.analytics/spring-analytics@2.0.0.RELEASE",
"/packages/spring-asm-3.0.7.RELEASE.jar": "pkg:maven/org.springframework/spring-asm@3.0.7.RELEASE",
"/packages/spring-batch-core-4.2.1.RELEASE.jar": "pkg:maven/org.springframework.batch/spring-batch-core@4.2.1.RELEASE",
"/packages/spring-boot-3.1.2.jar": "pkg:maven/org.springframework.boot/spring-boot@3.1.2",
"/packages/spring-cloud-app-broker-core-1.6.1.jar": "pkg:maven/org.springframework.cloud/spring-cloud-app-broker-core@1.6.1",
"/packages/spring-cql-1.5.11.RELEASE.jar": "pkg:maven/org.springframework.data/spring-cql@1.5.11.RELEASE",
"/packages/spring-credhub-core-1.0.1.RELEASE.jar": "pkg:maven/org.springframework.credhub/spring-credhub-core@1.0.1.RELEASE",
"/packages/spring-flex-1.0.3.RELEASE.jar": "pkg:maven/org.springframework.flex/spring-flex@1.0.3.RELEASE",
"/packages/spring-graphql-1.2.2.jar": "pkg:maven/org.springframework.graphql/spring-graphql@1.2.2",
"/packages/spring-hateoas-2.1.0.jar": "pkg:maven/org.springframework.hateoas/spring-hateoas@2.1.0",
"/packages/spring-integration-amqp-6.0.5.jar": "pkg:maven/org.springframework.integration/spring-integration-amqp@6.0.5",
"/packages/spring-kafka-3.0.9.jar": "pkg:maven/org.springframework.kafka/spring-kafka@3.0.9",
"/packages/spring-security-core-6.0.2.jar": "pkg:maven/org.springframework.security/spring-security-core@6.0.2",
"/packages/spring-security-kerberos-core-1.0.1.RELEASE.jar": "pkg:maven/org.springframework.security.kerberos/spring-security-kerberos-core@1.0.1.RELEASE",
"/packages/spring-security-oauth-2.5.1.RELEASE.jar": "pkg:maven/org.springframework.security.oauth/spring-security-oauth@2.5.1.RELEASE",
"/packages/spring-security-oauth2-autoconfigure-2.5.9.jar": "pkg:maven/org.springframework.security.oauth.boot/spring-security-oauth2-autoconfigure@2.5.9",
"/packages/spring-security-saml2-core-1.0.10.RELEASE.jar": "pkg:maven/org.springframework.security.extensions/spring-security-saml2-core@1.0.10.RELEASE",
"/packages/spring-session-core-3.0.0.jar": "pkg:maven/org.springframework.session/spring-session-core@3.0.0",
"/packages/spring-social-core-1.1.2.RELEASE.jar": "pkg:maven/org.springframework.social/spring-social-core@1.1.2.RELEASE",
"/packages/spring-vault-core-3.0.1.jar": "pkg:maven/org.springframework.vault/spring-vault-core@3.0.1",
"/packages/spring-webmvc-3.1.4.RELEASE.jar": "pkg:maven/org.springframework/spring-webmvc@3.1.4.RELEASE",
"/packages/spring-xml-3.0.3.RELEASE.jar": "pkg:maven/org.springframework.ws/spring-xml@3.0.3.RELEASE",
"/packages/storm-core-1.2.2.jar:cheshire:cheshire": "pkg:maven/cheshire/cheshire@5.3.1",
"/packages/storm-core-1.2.2.jar:clj-time:clj-time": "pkg:maven/clj-time/clj-time@0.8.0",
"/packages/storm-core-1.2.2.jar:clout:clout": "pkg:maven/clout/clout@1.2.0",
"/packages/storm-core-1.2.2.jar:com.fasterxml.jackson.core:jackson-core": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.9.4",
"/packages/storm-core-1.2.2.jar:com.fasterxml.jackson.dataformat:jackson-dataformat-smile": "pkg:maven/com.fasterxml.jackson.dataformat/jackson-dataformat-smile@2.9.4",
"/packages/storm-core-1.2.2.jar:com.google.guava:guava": "pkg:maven/com.google.guava/guava@16.0.1",
"/packages/storm-core-1.2.2.jar:com.twitter:carbonite": "pkg:maven/com.twitter/carbonite@1.5.0",
"/packages/storm-core-1.2.2.jar:commons-codec:commons-codec": "pkg:maven/commons-codec/commons-codec@1.6",
"/packages/storm-core-1.2.2.jar:commons-collections:commons-collections": "pkg:maven/commons-collections/commons-collections@3.2.2",
"/packages/storm-core-1.2.2.jar:commons-fileupload:commons-fileupload": "pkg:maven/commons-fileupload/commons-fileupload@1.3.2",
"/packages/storm-core-1.2.2.jar:commons-io:commons-io": "pkg:maven/commons-io/commons-io@2.5",
"/packages/storm-core-1.2.2.jar:commons-lang:commons-lang": "pkg:maven/commons-lang/commons-lang@2.5",
"/packages/storm-core-1.2.2.jar:compojure:compojure": "pkg:maven/compojure/compojure@1.1.9",
"/packages/storm-core-1.2.2.jar:hiccup:hiccup": "pkg:maven/hiccup/hiccup@0.3.6",
"/packages/storm-core-1.2.2.jar:io.netty:netty": "pkg:maven/io.netty/netty@3.9.9.Final",
"/packages/storm-core-1.2.2.jar:joda-time:joda-time": "pkg:maven/joda-time/joda-time@2.3",
"/packages/storm-core-1.2.2.jar:metrics-clojure:metrics-clojure": "pkg:maven/metrics-clojure/metrics-clojure@2.5.1",
"/packages/storm-core-1.2.2.jar:ns-tracker:ns-tracker": "pkg:maven/ns-tracker/ns-tracker@0.2.2",
"/packages/storm-core-1.2.2.jar:org.apache.commons:commons-compress": "pkg:maven/org.apache.commons/commons-compress@1.4.1",
"/packages/storm-core-1.2.2.jar:org.apache.commons:commons-exec": "pkg:maven/org.apache.commons/commons-exec@1.1",
"/packages/storm-core-1.2.2.jar:org.apache.curator:curator-client": "pkg:maven/org.apache.curator/curator-client@4.0.1",
"/packages/storm-core-1.2.2.jar:org.apache.curator:curator-framework": "pkg:maven/org.apache.curator/curator-framework@4.0.1",
"/packages/storm-core-1.2.2.jar:org.apache.curator:curator-recipes": "pkg:maven/org.apache.curator/curator-recipes@4.0.1",
"/packages/storm-core-1.2.2.jar:org.apache.hadoop:hadoop-auth": "pkg:maven/org.apache.hadoop/hadoop-auth@2.6.1",
"/packages/storm-core-1.2.2.jar:org.apache.httpcomponents:httpclient": "pkg:maven/org.apache.httpcomponents/httpclient@4.3.3",
"/packages/storm-core-1.2.2.jar:org.apache.httpcomponents:httpcore": "pkg:maven/org.apache.httpcomponents/httpcore@4.4.1",
"/packages/storm-core-1.2.2.jar:org.clojure:java.jmx": "pkg:maven/org.clojure/java.jmx@0.3.1",
"/packages/storm-core-1.2.2.jar:org.clojure:math.numeric-tower": "pkg:maven/org.clojure/math.numeric-tower@0.0.1",
"/packages/storm-core-1.2.2.jar:org.clojure:tools.cli": "pkg:maven/org.clojure/tools.cli@0.2.4",
"/packages/storm-core-1.2.2.jar:org.clojure:tools.logging": "pkg:maven/org.clojure/tools.logging@0.2.3",
"/packages/storm-core-1.2.2.jar:org.clojure:tools.macro": "pkg:maven/org.clojure/tools.macro@0.1.0",
"/packages/storm-core-1.2.2.jar:org.clojure:tools.namespace": "pkg:maven/org.clojure/tools.namespace@0.2.4",
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-client": "pkg:maven/org.eclipse.jetty/jetty-client@7.6.13.v20130916",
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-continuation": "pkg:maven/org.eclipse.jetty/jetty-continuation@7.6.13.v20130916",
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-http": "pkg:maven/org.eclipse.jetty/jetty-http@7.6.13.v20130916",
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-io": "pkg:maven/org.eclipse.jetty/jetty-io@7.6.13.v20130916",
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-security": "pkg:maven/org.eclipse.jetty/jetty-security@7.6.13.v20130916",
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-server": "pkg:maven/org.eclipse.jetty/jetty-server@7.6.13.v20130916",
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-servlet": "pkg:maven/org.eclipse.jetty/jetty-servlet@7.6.13.v20130916",
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-servlets": "pkg:maven/org.eclipse.jetty/jetty-servlets@7.6.13.v20130916",
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-util": "pkg:maven/org.eclipse.jetty/jetty-util@7.6.13.v20130916",
"/packages/storm-core-1.2.2.jar:org.jgrapht:jgrapht-core": "pkg:maven/org.jgrapht/jgrapht-core@0.9.0",
"/packages/storm-core-1.2.2.jar:org.yaml:snakeyaml": "pkg:maven/org.yaml/snakeyaml@1.11",
"/packages/storm-core-1.2.2.jar:ring:ring-codec": "pkg:maven/ring/ring-codec@1.0.0",
"/packages/storm-core-1.2.2.jar:ring:ring-core": "pkg:maven/ring/ring-core@1.3.1",
"/packages/storm-core-1.2.2.jar:ring:ring-devel": "pkg:maven/ring/ring-devel@1.3.1",
"/packages/storm-core-1.2.2.jar:ring:ring-jetty-adapter": "pkg:maven/ring/ring-jetty-adapter@1.3.1",
"/packages/storm-core-1.2.2.jar:ring:ring-json": "pkg:maven/ring/ring-json@0.3.1",
"/packages/storm-core-1.2.2.jar:ring:ring-servlet": "pkg:maven/ring/ring-servlet@1.3.1",
"/packages/storm-core-1.2.2.jar": "pkg:maven/org.apache.storm/storm-core@1.2.2",
"/packages/tapestry-core-5.8.1.jar": "pkg:maven/org.apache.tapestry/tapestry-core@5.8.1",
"/packages/tika-core-1.26.jar": "pkg:maven/org.apache.tika/tika-core@1.26",
"/packages/tomcat-catalina-11.0.0-M1.jar": "pkg:maven/org.apache.tomcat/tomcat-catalina@11.0.0-M1",
"/packages/tomcat-embed-core-11.0.0-M7.jar": "pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@11.0.0-M7",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/commons-codec-1.2.jar": "pkg:maven/commons-codec/commons-codec@1.2",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/commons-httpclient-3.1.jar": "pkg:maven/org.apache/commons-httpclient@3.1",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/commons-logging-1.0.4.jar": "pkg:maven/commons-logging/commons-logging@1.0.4",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/log4j-1.2.9.jar": "pkg:maven/log4j/log4j@1.2.9",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:commons-codec:commons-codec": "pkg:maven/commons-codec/commons-codec@1.4",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:commons-lang:commons-lang": "pkg:maven/commons-lang/commons-lang@2.5",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:commons-logging:commons-logging": "pkg:maven/commons-logging/commons-logging@1.1.1",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:org.apache.httpcomponents:httpclient": "pkg:maven/org.apache.httpcomponents/httpclient@4.1.1",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:org.apache.httpcomponents:httpcore": "pkg:maven/org.apache.httpcomponents/httpcore@4.1",
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:org.easymock:easymock": "pkg:maven/org.easymock/easymock@2.4",
"/packages/TwilioNotifier.hpi": "pkg:maven/com.twilio.jenkins/TwilioNotifier@0.2.1",
"/packages/undertow-core-2.3.4.Final.jar": "pkg:maven/io.undertow/undertow-core@2.3.4.Final",
"/packages/vaadin-client-8.11.3.jar": "pkg:maven/com.vaadin/vaadin-client@8.11.3",
"/packages/velocity-1.7.jar": "pkg:maven/org.apache.velocity/velocity@1.7",
"/packages/vertx-web-4.3.7.jar": "pkg:maven/io.vertx/vertx-web@4.3.7",
"/packages/wicket-core-9.2.0.jar": "pkg:maven/org.apache.wicket/wicket-core@9.2.0",
"/packages/xalan-2.7.2.jar": "pkg:maven/xalan/xalan@2.7.2",
"/packages/xmlpull-1.1.3.1.jar": "pkg:maven/xmlpull/xmlpull@1.1.3.1",
// "/packages/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3/xpp3_min@1.1.4c",
"/packages/xstream-1.4.11.1.jar": "pkg:maven/com.thoughtworks.xstream/xstream@1.4.11.1",
"/packages/xstream-1.4.19.jar": "pkg:maven/com.thoughtworks.xstream/xstream@1.4.19",
"/packages/xwiki-commons-xml-15.1.jar": "pkg:maven/org.xwiki.commons/xwiki-commons-xml@15.1",
"/packages/xwiki-platform-oldcore-15.3.jar": "pkg:maven/org.xwiki.platform/xwiki-platform-oldcore@15.3",
"/packages/zookeeper-3.7.1.jar": "pkg:maven/org.apache.zookeeper/zookeeper@3.7.1",
}

Some files were not shown because too many files have changed in this diff Show More