mirror of
https://github.com/anchore/syft.git
synced 2026-10-20 10:02:24 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0748945c83 | ||
|
|
185d0d1bfa | ||
|
|
d16ecdf715 | ||
|
|
68cf57ed03 | ||
|
|
f6c8057977 | ||
|
|
87e57aa925 | ||
|
|
eed35ec9ce | ||
|
|
b23879fd37 | ||
|
|
30f0686353 | ||
|
|
235ad2e749 | ||
|
|
127fac8ca9 | ||
|
|
37bb95f5c9 | ||
|
|
1067dc2ce9 | ||
|
|
21878784a8 | ||
|
|
86005d1593 | ||
|
|
45625dae94 | ||
|
|
38d5ef2c84 | ||
|
|
44e5480238 | ||
|
|
7b1af8721d | ||
|
|
8f57d22f63 | ||
|
|
351c683cb4 | ||
|
|
534a5f54b0 | ||
|
|
8a414b5366 | ||
|
|
e34adea749 | ||
|
|
8314c0d2cb |
@@ -1 +1,2 @@
|
||||
enforce-v0: true # don't make breaking-change label bump major version before 1.0.
|
||||
title: ""
|
||||
@@ -6,10 +6,6 @@ inputs:
|
||||
description: "Go version to install"
|
||||
required: true
|
||||
default: "1.21.x"
|
||||
use-go-cache:
|
||||
description: "Restore go cache"
|
||||
required: true
|
||||
default: "true"
|
||||
cache-key-prefix:
|
||||
description: "Prefix all cache keys with this value"
|
||||
required: true
|
||||
@@ -25,6 +21,7 @@ inputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# note: go mod and build is automatically cached on default with v4+
|
||||
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
@@ -36,38 +33,13 @@ runs:
|
||||
path: ${{ github.workspace }}/.tmp
|
||||
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
|
||||
|
||||
# note: we need to keep restoring the go mod cache before bootstrapping tools since `go install` is used in
|
||||
# some installations of project tools.
|
||||
- name: Restore go module cache
|
||||
id: go-mod-cache
|
||||
if: inputs.use-go-cache == 'true'
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-go-mod-${{ inputs.go-version }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ inputs.cache-key-prefix }}-${{ runner.os }}-go-mod-${{ inputs.go-version }}-
|
||||
|
||||
- name: (cache-miss) Bootstrap project tools
|
||||
shell: bash
|
||||
if: steps.tool-cache.outputs.cache-hit != 'true'
|
||||
run: make bootstrap-tools
|
||||
|
||||
- name: Restore go build cache
|
||||
id: go-cache
|
||||
if: inputs.use-go-cache == 'true'
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
key: ${{ inputs.cache-key-prefix }}-${{ inputs.build-cache-key-prefix }}-${{ runner.os }}-go-build-${{ inputs.go-version }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ inputs.cache-key-prefix }}-${{ inputs.build-cache-key-prefix }}-${{ runner.os }}-go-build-${{ inputs.go-version }}-
|
||||
|
||||
- name: (cache-miss) Bootstrap go dependencies
|
||||
- name: Bootstrap go dependencies
|
||||
shell: bash
|
||||
if: steps.go-mod-cache.outputs.cache-hit != 'true' && inputs.use-go-cache == 'true'
|
||||
run: make bootstrap-go
|
||||
|
||||
- name: Install apt packages
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
# the job by event.
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@6a28655e3dcb49cb0840ea372fd6d17733edd8a4 #v2.21.8
|
||||
uses: github/codeql-action/init@fdcae64e1484d349b3366718cdfef3d404390e85 #v2.22.1
|
||||
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@6a28655e3dcb49cb0840ea372fd6d17733edd8a4 #v2.21.8
|
||||
uses: github/codeql-action/autobuild@fdcae64e1484d349b3366718cdfef3d404390e85 #v2.22.1
|
||||
|
||||
# ℹ️ 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@6a28655e3dcb49cb0840ea372fd6d17733edd8a4 #v2.21.8
|
||||
uses: github/codeql-action/analyze@fdcae64e1484d349b3366718cdfef3d404390e85 #v2.22.1
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
environment: release
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- name: Check if tag already exists
|
||||
# note: this will fail if the tag already exists
|
||||
@@ -95,7 +95,7 @@ jobs:
|
||||
contents: write
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -149,7 +149,7 @@ jobs:
|
||||
with:
|
||||
artifact-name: sbom.spdx.json
|
||||
|
||||
- uses: 8398a7/action-slack@49aa08e51e8782f49c601d79ec72d07fd39a4612 #v3.15.1
|
||||
- uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #v3.15.1
|
||||
continue-on-error: true
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
@@ -158,9 +158,3 @@ jobs:
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
|
||||
if: ${{ success() }}
|
||||
|
||||
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 #v3.1.3
|
||||
with:
|
||||
name: artifacts
|
||||
path: dist/**/*
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0
|
||||
with:
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- uses: actions/setup-go@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
with:
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0
|
||||
with:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
name: "Static analysis"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
name: "Unit tests"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
name: "Integration tests"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -96,7 +96,7 @@ jobs:
|
||||
name: "Build snapshot artifacts"
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- name: Download snapshot build
|
||||
uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- name: Download snapshot build
|
||||
uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2
|
||||
@@ -191,7 +191,7 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 #v4.1.0
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
+27
-36
@@ -153,56 +153,47 @@ sequenceDiagram
|
||||
|
||||
### Syft Catalogers
|
||||
|
||||
##### Summary
|
||||
|
||||
Catalogers are the way in which syft is able to identify and construct packages given some amount of source metadata.
|
||||
For example, Syft can locate and process `package-lock.json` files when performing filesystem scans.
|
||||
See: [how to specify file globs](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/javascript/cataloger.go#L16-L21)
|
||||
and an implementation of the [package-lock.json parser](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/javascript/cataloger.go#L16-L21) for a quick review.
|
||||
Catalogers are the way in which syft is able to identify and construct packages given a set a targeted list of files.
|
||||
For example, a cataloger can ask syft for all `package-lock.json` files in order to parse and raise up javascript packages
|
||||
(see [how file globs](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/javascript/cataloger.go#L16-L21) and
|
||||
[file parser functions](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/javascript/cataloger.go#L16-L21) are used
|
||||
for a quick example).
|
||||
|
||||
From a high level catalogers have the following properties:
|
||||
|
||||
- They are independent from one another. The java cataloger has no idea of the processes, assumptions, or results of the python cataloger, for example.
|
||||
- _They are independent from one another_. The java cataloger has no idea of the processes, assumptions, or results of the python cataloger, for example.
|
||||
|
||||
- They do not know what source is being analyzed. Are we analyzing a local directory? an image? if so, the squashed representation or all layers? The catalogers do not know the answers to these questions. Only that there is an interface to query for file paths and contents from an underlying "source" being scanned.
|
||||
- _They do not know what source is being analyzed_. Are we analyzing a local directory? an image? if so, the squashed representation or all layers? The catalogers do not know the answers to these questions. Only that there is an interface to query for file paths and contents from an underlying "source" being scanned.
|
||||
|
||||
- _Packages created by the cataloger should not be mutated after they are created_. There is one exception made for adding CPEs to a package after the cataloging phase, but that will most likely be moved back into the cataloger in the future.
|
||||
|
||||
- Packages created by the cataloger should not be mutated after they are created. There is one exception made for adding CPEs to a package after the cataloging phase, but that will most likely be moved back into the cataloger in the future.
|
||||
|
||||
#### Building a new Cataloger
|
||||
|
||||
Catalogers must fulfill the interface [found here](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger.go).
|
||||
This means that when building a new cataloger, the new struct must implement both method signatures of `Catalog` and `Name`.
|
||||
Catalogers must fulfill the [`pkg.Cataloger` interface](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger.go) in order to add packages to the SBOM.
|
||||
All catalogers should be added to:
|
||||
- the [global list of catalogers](https://github.com/anchore/syft/blob/9995950c70e849f9921919faffbfcf46401f71f3/syft/pkg/cataloger/cataloger.go#L92-L125)
|
||||
- at least one source-specific list, today the two lists are [directory catalogers and image catalogers](https://github.com/anchore/syft/blob/9995950c70e849f9921919faffbfcf46401f71f3/syft/pkg/cataloger/cataloger.go#L39-L89)
|
||||
|
||||
A top level view of the functions that construct all the catalogers can be found [here](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/cataloger.go).
|
||||
When an author has finished writing a new cataloger this is the spot to plug in the new catalog constructor.
|
||||
For reference, catalogers are [invoked within syft](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/catalog.go#L41-L100) one after the other, and can be invoked in parallel.
|
||||
|
||||
For a top level view of how the catalogers are used see [this function](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/catalog.go#L41-L100) as a reference. It ranges over all catalogers passed as an argument and invokes the `Catalog` method:
|
||||
`generic.NewCataloger` is an abstraction syft used to make writing common components easier (see the [apkdb cataloger](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/apkdb/cataloger.go) for example usage).
|
||||
It takes the following information as input:
|
||||
- A `catalogerName` to identify the cataloger uniquely among all other catalogers.
|
||||
- Pairs of file globs as well as parser functions to parse those files. These parser functions return a slice of [`pkg.Package`](https://github.com/anchore/syft/blob/9995950c70e849f9921919faffbfcf46401f71f3/syft/pkg/package.go#L19) as well as a slice of [`artifact.Relationship`](https://github.com/anchore/syft/blob/9995950c70e849f9921919faffbfcf46401f71f3/syft/artifact/relationship.go#L31) to describe how the returned packages are related. See this [the apkdb cataloger parser function](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/apkdb/parse_apk_db.go#L22-L102) as an example.
|
||||
|
||||
Each cataloger has its own `Catalog` method, but this does not mean that they are all vastly different.
|
||||
Take a look at the `apkdb` cataloger for alpine to see how it [constructs a generic.NewCataloger](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/apkdb/cataloger.go).
|
||||
|
||||
`generic.NewCataloger` is an abstraction syft uses to make writing common components easier. First, it takes the `catalogerName` to identify the cataloger.
|
||||
On the other side of the call it uses two key pieces which inform the cataloger how to identify and return packages, the `globPatterns` and the `parseFunction`:
|
||||
- The first piece is a `parseByGlob` matching pattern used to identify the files that contain the package metadata.
|
||||
See [here for the APK example](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/apk_metadata.go#L16-L41).
|
||||
- The other is a `parseFunction` which informs the cataloger what to do when it has found one of the above matches files.
|
||||
See this [link for an example](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/apkdb/parse_apk_db.go#L22-L102).
|
||||
|
||||
If you're unsure about using the `Generic Cataloger` and think the use case being filled requires something more custom
|
||||
just file an issue or ask in our slack, and we'd be more than happy to help on the design.
|
||||
|
||||
Identified packages share a common struct so be sure that when the new cataloger is constructing a new package it is using the [`Package` struct](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/package.go#L16-L31).
|
||||
|
||||
Metadata Note: Identified packages are also assigned specific metadata that can be unique to their environment.
|
||||
See [this folder](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg) for examples of the different metadata types.
|
||||
Identified packages share a common `pkg.Package` struct so be sure that when the new cataloger is constructing a new package it is using the [`Package` struct](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/package.go#L16-L31).
|
||||
If you want to return more information than what is available on the `pkg.Package` struct then you can do so in the `pkg.Package.Metadata` section of the struct, which is unique for each [`pkg.Type`](https://github.com/anchore/syft/blob/v0.70.0/syft/pkg/type.go).
|
||||
See [the `pkg` package](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg) for examples of the different metadata types that are supported today.
|
||||
These are plugged into the `MetadataType` and `Metadata` fields in the above struct. `MetadataType` informs which type is being used. `Metadata` is an interface converted to that type.
|
||||
|
||||
Finally, here is an example of where the package construction is done in the apk cataloger. The first link is where `newPackage` is called in the `parseFunction`. The second link shows the package construction:
|
||||
- [Call for new package](https://github.com/anchore/syft/blob/v0.70.0/syft/pkg/cataloger/apkdb/parse_apk_db.go#L106)
|
||||
- [APK Package Constructor](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/apkdb/package.go#L12-L27)
|
||||
Finally, here is an example of where the package construction is done within the apk cataloger:
|
||||
- [Calling the APK package constructor from the parser function](https://github.com/anchore/syft/blob/v0.70.0/syft/pkg/cataloger/apkdb/parse_apk_db.go#L106)
|
||||
- [The APK package constructor itself](https://github.com/anchore/syft/tree/v0.70.0/syft/pkg/cataloger/apkdb/package.go#L12-L27)
|
||||
|
||||
Interested in building a new cataloger? Checkout the [list of issues with the `new-cataloger` label](https://github.com/anchore/syft/issues?q=is%3Aopen+is%3Aissue+label%3Anew-cataloger+no%3Aassignee)!
|
||||
If you have questions about implementing a cataloger feel free to file an issue or reach out to us [on slack](https://anchore.com/slack)!
|
||||
|
||||
If you have more questions about implementing a cataloger or questions about one you might be currently working
|
||||
always feel free to file an issue or reach out to us [on slack](https://anchore.com/slack).
|
||||
|
||||
#### Searching for files
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ GOLANGCILINT_VERSION := v1.54.2
|
||||
GOSIMPORTS_VERSION := v0.3.8
|
||||
BOUNCER_VERSION := v0.4.0
|
||||
CHRONICLE_VERSION := v0.8.0
|
||||
GORELEASER_VERSION := v1.20.0
|
||||
GORELEASER_VERSION := v1.21.2
|
||||
YAJSV_VERSION := v1.4.1
|
||||
COSIGN_VERSION := v2.2.0
|
||||
QUILL_VERSION := v0.4.1
|
||||
|
||||
@@ -390,11 +390,11 @@ syft convert <ORIGINAL-SBOM-FILE> -o <NEW-SBOM-FORMAT>[=<NEW-SBOM-FILE>]
|
||||
This feature is experimental and data might be lost when converting formats. Packages are the main SBOM component easily transferable across formats, whereas files and relationships, as well as other information Syft doesn't support, are more likely to be lost.
|
||||
|
||||
We support formats with wide community usage AND good encode/decode support by Syft. The supported formats are:
|
||||
- Syft JSON
|
||||
- SPDX 2.2 JSON
|
||||
- SPDX 2.2 tag-value
|
||||
- CycloneDX 1.4 JSON
|
||||
- CycloneDX 1.4 XML
|
||||
- Syft JSON (```-o syft-json```)
|
||||
- SPDX 2.2 JSON (```-o spdx-json```)
|
||||
- SPDX 2.2 tag-value (```-o spdx-tag-value```)
|
||||
- CycloneDX 1.4 JSON (```-o cyclonedx-json```)
|
||||
- CycloneDX 1.4 XML (```-o cyclonedx-xml```)
|
||||
|
||||
Conversion example:
|
||||
```sh
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"slices"
|
||||
|
||||
"github.com/anchore/clio"
|
||||
"github.com/anchore/fangs"
|
||||
"github.com/anchore/syft/syft/formats"
|
||||
"github.com/anchore/syft/syft/formats/table"
|
||||
"github.com/anchore/syft/syft/formats/template"
|
||||
@@ -30,7 +31,7 @@ func DefaultOutput() MultiOutput {
|
||||
|
||||
func (o *MultiOutput) AddFlags(flags clio.FlagSet) {
|
||||
flags.StringArrayVarP(&o.Outputs, "output", "o",
|
||||
fmt.Sprintf("report output format, options=%v", formats.AllIDs()))
|
||||
fmt.Sprintf("report output format (<format>=<file> to output to a file), formats=%v", formats.AllIDs()))
|
||||
|
||||
flags.StringVarP(&o.OutputTemplatePath, "template", "t",
|
||||
"specify the path to a Go template file")
|
||||
@@ -63,7 +64,7 @@ func (o *SingleOutput) SBOMWriter(file string) (sbom.Writer, error) {
|
||||
return makeSBOMWriter([]string{o.Output}, file, o.OutputTemplatePath)
|
||||
}
|
||||
|
||||
// OutputFile is only the --file argument
|
||||
// Deprecated: OutputFile is only the --file argument
|
||||
type OutputFile struct {
|
||||
File string `yaml:"file" json:"file" mapstructure:"file"` // --file, the file to write report output to
|
||||
}
|
||||
@@ -76,6 +77,11 @@ var _ interface {
|
||||
func (o *OutputFile) AddFlags(flags clio.FlagSet) {
|
||||
flags.StringVarP(&o.File, "file", "",
|
||||
"file to write the default report output to (default is STDOUT)")
|
||||
|
||||
if pfp, ok := flags.(fangs.PFlagSetProvider); ok {
|
||||
flagSet := pfp.PFlagSet()
|
||||
flagSet.Lookup("file").Deprecated = "use: output"
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OutputFile) PostLoad() error {
|
||||
|
||||
@@ -183,11 +183,7 @@ func Test_newSBOMMultiWriter(t *testing.T) {
|
||||
switch w := mw.writers[i].(type) {
|
||||
case *sbomStreamWriter:
|
||||
assert.Equal(t, string(w.format.ID()), e.format)
|
||||
if e.file != "" {
|
||||
assert.NotNil(t, w.out)
|
||||
} else {
|
||||
assert.NotNil(t, w.out)
|
||||
}
|
||||
assert.NotNil(t, w.out)
|
||||
if e.file != "" {
|
||||
assert.FileExists(t, tmp+e.file)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ require (
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501
|
||||
github.com/anchore/stereoscope v0.0.0-20230919183137-5841b53a0375
|
||||
github.com/anchore/stereoscope v0.0.0-20230925132944-bf05af58eb44
|
||||
// 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
|
||||
@@ -25,12 +25,12 @@ require (
|
||||
github.com/charmbracelet/lipgloss v0.8.0
|
||||
github.com/dave/jennifer v1.7.0
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
|
||||
github.com/docker/distribution v2.8.2+incompatible
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v24.0.6+incompatible
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/facebookincubator/nvdtools v0.1.5
|
||||
github.com/github/go-spdx/v2 v2.2.0
|
||||
github.com/gkampitakis/go-snaps v0.4.10
|
||||
github.com/gkampitakis/go-snaps v0.4.11
|
||||
github.com/go-git/go-billy/v5 v5.5.0
|
||||
github.com/go-git/go-git/v5 v5.9.0
|
||||
github.com/go-test/deep v1.1.0
|
||||
@@ -53,30 +53,33 @@ 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.5
|
||||
github.com/saferwall/pe v1.4.7
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
|
||||
github.com/sassoftware/go-rpmutils v0.2.0
|
||||
// pinned to pull in 386 arch fix: https://github.com/scylladb/go-set/commit/cc7b2070d91ebf40d233207b633e28f5bd8f03a5
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e
|
||||
github.com/sergi/go-diff v1.3.1
|
||||
github.com/spdx/tools-golang v0.5.3
|
||||
github.com/spf13/afero v1.9.5
|
||||
github.com/spf13/afero v1.10.0
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/vbatts/go-mtree v0.5.3
|
||||
github.com/vifraa/gopom v1.0.0
|
||||
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651
|
||||
github.com/wagoodman/go-progress v0.0.0-20230911172108-cf810b7e365c
|
||||
github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1
|
||||
golang.org/x/mod v0.12.0
|
||||
golang.org/x/net v0.15.0
|
||||
golang.org/x/term v0.12.0 // indirect
|
||||
golang.org/x/mod v0.13.0
|
||||
golang.org/x/net v0.16.0
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.25.0
|
||||
modernc.org/sqlite v1.26.0
|
||||
)
|
||||
|
||||
require github.com/sanity-io/litter v1.5.5
|
||||
require (
|
||||
github.com/distribution/reference v0.5.0
|
||||
github.com/sanity-io/litter v1.5.5
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
@@ -203,9 +206,9 @@ require (
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
golang.org/x/crypto v0.13.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
|
||||
@@ -112,8 +112,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-20230919183137-5841b53a0375 h1:lpeR4D5PMFXg80QVJgwlJs0QyS8FTBVuFW45Y+3Tat0=
|
||||
github.com/anchore/stereoscope v0.0.0-20230919183137-5841b53a0375/go.mod h1:75uRHom5WV5ENe3iSK2B37BQvB+47o9HYjpCYaSwlPQ=
|
||||
github.com/anchore/stereoscope v0.0.0-20230925132944-bf05af58eb44 h1:dKMvcpgqsRrX1ZWyqG53faVW+BahlaAO1RUEc7/rOjA=
|
||||
github.com/anchore/stereoscope v0.0.0-20230925132944-bf05af58eb44/go.mod h1:RtbeDCho0pxkPqrB1QNf/Jlxfc9juLmtYZAf2UbpJfk=
|
||||
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=
|
||||
@@ -213,10 +213,12 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da h1:ZOjWpVsFZ06eIhnh4mkaceTiVoktdU67+M7KDHJ268M=
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v24.0.0+incompatible h1:0+1VshNwBQzQAx9lOl+OYCTCEAD8fKs/qeXMx3O0wqM=
|
||||
github.com/docker/cli v24.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE=
|
||||
github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||
@@ -275,8 +277,8 @@ github.com/gkampitakis/ciinfo v0.2.5 h1:K0mac90lGguc1conc46l0YEsB7/nioWCqSnJp/6z
|
||||
github.com/gkampitakis/ciinfo v0.2.5/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
|
||||
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
|
||||
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
|
||||
github.com/gkampitakis/go-snaps v0.4.10 h1:rUcTH4k6+rzw6ylDALMifzw2c/f9cG3NZe/n+7Ygdr4=
|
||||
github.com/gkampitakis/go-snaps v0.4.10/go.mod h1:N4TpqxI4CqKUfHzDFqrqZ5UP0I0ESz2g2NMslh7MiJw=
|
||||
github.com/gkampitakis/go-snaps v0.4.11 h1:7qKaozbTQEvHeG0bt6osdjdTDTnWYdIrLx43a7DEDu4=
|
||||
github.com/gkampitakis/go-snaps v0.4.11/go.mod h1:N4TpqxI4CqKUfHzDFqrqZ5UP0I0ESz2g2NMslh7MiJw=
|
||||
github.com/glebarez/go-sqlite v1.20.3 h1:89BkqGOXR9oRmG58ZrzgoY/Fhy5x0M+/WV48U5zVrZ4=
|
||||
github.com/glebarez/go-sqlite v1.20.3/go.mod h1:u3N6D/wftiAzIOJtZl6BmedqxmmkDfH3q+ihjqxC9u0=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
@@ -665,8 +667,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.5 h1:ACIe9QnLTdiRIbuN3BbEUI8SqCQmNrPBb7O2lJTmsK4=
|
||||
github.com/saferwall/pe v1.4.5/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
|
||||
github.com/saferwall/pe v1.4.7 h1:A+G3DxX49paJ5OsxBfHKskhyDtmTjShlDmBd81IsHlQ=
|
||||
github.com/saferwall/pe v1.4.7/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
|
||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
||||
@@ -702,8 +704,8 @@ github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQr
|
||||
github.com/spdx/tools-golang v0.5.3/go.mod h1:/ETOahiAo96Ob0/RAIBmFZw6XN0yTnyr/uFZm2NTMhI=
|
||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
|
||||
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
@@ -777,8 +779,8 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIqV3d+DOxazTR9v+zgj8+VYuQBzPgBZvWBHA=
|
||||
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20=
|
||||
github.com/wagoodman/go-progress v0.0.0-20230911172108-cf810b7e365c h1:mM8T8YhiD19d2wYv3vqZn8xpe1ZFJrUJCGlK4IV05xM=
|
||||
github.com/wagoodman/go-progress v0.0.0-20230911172108-cf810b7e365c/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA=
|
||||
github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 h1:0KGbf+0SMg+UFy4e1A/CPVvXn21f1qtWdeJwxZFoQG8=
|
||||
github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@@ -843,8 +845,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -883,8 +885,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -933,8 +935,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos=
|
||||
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1052,16 +1054,16 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1349,8 +1351,8 @@ modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o=
|
||||
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
|
||||
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
|
||||
modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw=
|
||||
modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
|
||||
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=
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at 2023-07-11 11:55:35.533815 -0400 EDT m=+0.695308614
|
||||
// This file was generated by robots at 2023-10-05 22:45:16.827263 -0400 EDT m=+0.138031521
|
||||
// using data from https://spdx.org/licenses/licenses.json
|
||||
package spdxlicense
|
||||
|
||||
const Version = "3.21"
|
||||
const Version = "3.22"
|
||||
|
||||
var licenseIDs = map[string]string{
|
||||
"0bsd": "0BSD",
|
||||
@@ -14,6 +14,7 @@ var licenseIDs = map[string]string{
|
||||
"adobe2006.0": "Adobe-2006",
|
||||
"adobe2006.0.0": "Adobe-2006",
|
||||
"adobeglyph": "Adobe-Glyph",
|
||||
"adobeutopia": "Adobe-Utopia",
|
||||
"adsl": "ADSL",
|
||||
"afl1": "AFL-1.1",
|
||||
"afl1.1": "AFL-1.1",
|
||||
@@ -145,6 +146,8 @@ var licenseIDs = map[string]string{
|
||||
"bsd3.0.0clause": "BSD-3-Clause",
|
||||
"bsd3.0.0clauseattribution": "BSD-3-Clause-Attribution",
|
||||
"bsd3.0.0clauseclear": "BSD-3-Clause-Clear",
|
||||
"bsd3.0.0clauseflex": "BSD-3-Clause-flex",
|
||||
"bsd3.0.0clausehp": "BSD-3-Clause-HP",
|
||||
"bsd3.0.0clauselbnl": "BSD-3-Clause-LBNL",
|
||||
"bsd3.0.0clausemodification": "BSD-3-Clause-Modification",
|
||||
"bsd3.0.0clausenomilitarylicense": "BSD-3-Clause-No-Military-License",
|
||||
@@ -152,9 +155,12 @@ var licenseIDs = map[string]string{
|
||||
"bsd3.0.0clausenonuclearlicense2014": "BSD-3-Clause-No-Nuclear-License-2014",
|
||||
"bsd3.0.0clausenonuclearwarranty": "BSD-3-Clause-No-Nuclear-Warranty",
|
||||
"bsd3.0.0clauseopenmpi": "BSD-3-Clause-Open-MPI",
|
||||
"bsd3.0.0clausesun": "BSD-3-Clause-Sun",
|
||||
"bsd3.0clause": "BSD-3-Clause",
|
||||
"bsd3.0clauseattribution": "BSD-3-Clause-Attribution",
|
||||
"bsd3.0clauseclear": "BSD-3-Clause-Clear",
|
||||
"bsd3.0clauseflex": "BSD-3-Clause-flex",
|
||||
"bsd3.0clausehp": "BSD-3-Clause-HP",
|
||||
"bsd3.0clauselbnl": "BSD-3-Clause-LBNL",
|
||||
"bsd3.0clausemodification": "BSD-3-Clause-Modification",
|
||||
"bsd3.0clausenomilitarylicense": "BSD-3-Clause-No-Military-License",
|
||||
@@ -162,9 +168,12 @@ var licenseIDs = map[string]string{
|
||||
"bsd3.0clausenonuclearlicense2014": "BSD-3-Clause-No-Nuclear-License-2014",
|
||||
"bsd3.0clausenonuclearwarranty": "BSD-3-Clause-No-Nuclear-Warranty",
|
||||
"bsd3.0clauseopenmpi": "BSD-3-Clause-Open-MPI",
|
||||
"bsd3.0clausesun": "BSD-3-Clause-Sun",
|
||||
"bsd3clause": "BSD-3-Clause",
|
||||
"bsd3clauseattribution": "BSD-3-Clause-Attribution",
|
||||
"bsd3clauseclear": "BSD-3-Clause-Clear",
|
||||
"bsd3clauseflex": "BSD-3-Clause-flex",
|
||||
"bsd3clausehp": "BSD-3-Clause-HP",
|
||||
"bsd3clauselbnl": "BSD-3-Clause-LBNL",
|
||||
"bsd3clausemodification": "BSD-3-Clause-Modification",
|
||||
"bsd3clausenomilitarylicense": "BSD-3-Clause-No-Military-License",
|
||||
@@ -172,6 +181,7 @@ var licenseIDs = map[string]string{
|
||||
"bsd3clausenonuclearlicense2014": "BSD-3-Clause-No-Nuclear-License-2014",
|
||||
"bsd3clausenonuclearwarranty": "BSD-3-Clause-No-Nuclear-Warranty",
|
||||
"bsd3clauseopenmpi": "BSD-3-Clause-Open-MPI",
|
||||
"bsd3clausesun": "BSD-3-Clause-Sun",
|
||||
"bsd4.0.0clause": "BSD-4-Clause",
|
||||
"bsd4.0.0clauseshortened": "BSD-4-Clause-Shortened",
|
||||
"bsd4.0.0clauseuc": "BSD-4-Clause-UC",
|
||||
@@ -189,8 +199,10 @@ var licenseIDs = map[string]string{
|
||||
"bsd4tahoe": "BSD-4.3TAHOE",
|
||||
"bsdadvertisingacknowledgement": "BSD-Advertising-Acknowledgement",
|
||||
"bsdattributionhpnddisclaimer": "BSD-Attribution-HPND-disclaimer",
|
||||
"bsdinfernonettverk": "BSD-Inferno-Nettverk",
|
||||
"bsdprotection": "BSD-Protection",
|
||||
"bsdsourcecode": "BSD-Source-Code",
|
||||
"bsdsystemics": "BSD-Systemics",
|
||||
"bsl1": "BSL-1.0",
|
||||
"bsl1.0": "BSL-1.0",
|
||||
"bsl1.0.0": "BSL-1.0",
|
||||
@@ -403,6 +415,7 @@ var licenseIDs = map[string]string{
|
||||
"cernohlw2.0": "CERN-OHL-W-2.0",
|
||||
"cernohlw2.0.0": "CERN-OHL-W-2.0",
|
||||
"cfitsio": "CFITSIO",
|
||||
"checkcvs": "check-cvs",
|
||||
"checkmk": "checkmk",
|
||||
"clartistic": "ClArtistic",
|
||||
"clips": "Clips",
|
||||
@@ -432,6 +445,7 @@ var licenseIDs = map[string]string{
|
||||
"cpol1": "CPOL-1.02",
|
||||
"cpol1.02": "CPOL-1.02",
|
||||
"cpol1.02.0": "CPOL-1.02",
|
||||
"cronyx": "Cronyx",
|
||||
"crossword": "Crossword",
|
||||
"crystalstacker": "CrystalStacker",
|
||||
"cuaopl1": "CUA-OPL-1.0",
|
||||
@@ -449,6 +463,9 @@ var licenseIDs = map[string]string{
|
||||
"dldeby2": "DL-DE-BY-2.0",
|
||||
"dldeby2.0": "DL-DE-BY-2.0",
|
||||
"dldeby2.0.0": "DL-DE-BY-2.0",
|
||||
"dldezero2": "DL-DE-ZERO-2.0",
|
||||
"dldezero2.0": "DL-DE-ZERO-2.0",
|
||||
"dldezero2.0.0": "DL-DE-ZERO-2.0",
|
||||
"doc": "DOC",
|
||||
"dotseqn": "Dotseqn",
|
||||
"drl1": "DRL-1.0",
|
||||
@@ -500,7 +517,9 @@ var licenseIDs = map[string]string{
|
||||
"eupl1.2.0": "EUPL-1.2",
|
||||
"eurosym": "Eurosym",
|
||||
"fair": "Fair",
|
||||
"fbm": "FBM",
|
||||
"fdkaac": "FDK-AAC",
|
||||
"fergusontwofish": "Ferguson-Twofish",
|
||||
"frameworx1": "Frameworx-1.0",
|
||||
"frameworx1.0": "Frameworx-1.0",
|
||||
"frameworx1.0.0": "Frameworx-1.0",
|
||||
@@ -511,6 +530,8 @@ var licenseIDs = map[string]string{
|
||||
"fsfullr": "FSFULLR",
|
||||
"fsfullrwd": "FSFULLRWD",
|
||||
"ftl": "FTL",
|
||||
"furuseth": "Furuseth",
|
||||
"fwlw": "fwlw",
|
||||
"gd": "GD",
|
||||
"gfdl1": "GFDL-1.1-only",
|
||||
"gfdl1+": "GFDL-1.1-or-later",
|
||||
@@ -658,11 +679,21 @@ var licenseIDs = map[string]string{
|
||||
"hp1986": "HP-1986",
|
||||
"hp1986.0": "HP-1986",
|
||||
"hp1986.0.0": "HP-1986",
|
||||
"hp1989": "HP-1989",
|
||||
"hp1989.0": "HP-1989",
|
||||
"hp1989.0.0": "HP-1989",
|
||||
"hpnd": "HPND",
|
||||
"hpnddec": "HPND-DEC",
|
||||
"hpnddoc": "HPND-doc",
|
||||
"hpnddocsell": "HPND-doc-sell",
|
||||
"hpndexportus": "HPND-export-US",
|
||||
"hpndexportusmodify": "HPND-export-US-modify",
|
||||
"hpndmarkuskuhn": "HPND-Markus-Kuhn",
|
||||
"hpndpbmplus": "HPND-Pbmplus",
|
||||
"hpndsellregexpr": "HPND-sell-regexpr",
|
||||
"hpndsellvariant": "HPND-sell-variant",
|
||||
"hpndsellvariantmitdisclaimer": "HPND-sell-variant-MIT-disclaimer",
|
||||
"hpnduc": "HPND-UC",
|
||||
"htmltidy": "HTMLTIDY",
|
||||
"ibmpibs": "IBM-pibs",
|
||||
"icu": "ICU",
|
||||
@@ -695,6 +726,7 @@ var licenseIDs = map[string]string{
|
||||
"jplimage": "JPL-image",
|
||||
"jpnic": "JPNIC",
|
||||
"json": "JSON",
|
||||
"kastrup": "Kastrup",
|
||||
"kazlib": "Kazlib",
|
||||
"knuthctan": "Knuth-CTAN",
|
||||
"lal1": "LAL-1.2",
|
||||
@@ -788,14 +820,18 @@ var licenseIDs = map[string]string{
|
||||
"lppl1.3c": "LPPL-1.3c",
|
||||
"lppl1a": "LPPL-1.3a",
|
||||
"lppl1c": "LPPL-1.3c",
|
||||
"lsof": "lsof",
|
||||
"lucidabitmapfonts": "Lucida-Bitmap-Fonts",
|
||||
"lzmasdk9": "LZMA-SDK-9.22",
|
||||
"lzmasdk9.11.0to9.20": "LZMA-SDK-9.11-to-9.20",
|
||||
"lzmasdk9.11to9.20": "LZMA-SDK-9.11-to-9.20",
|
||||
"lzmasdk9.22": "LZMA-SDK-9.22",
|
||||
"lzmasdk9.22.0": "LZMA-SDK-9.22",
|
||||
"lzmasdk9to9.20": "LZMA-SDK-9.11-to-9.20",
|
||||
"magaz": "magaz",
|
||||
"makeindex": "MakeIndex",
|
||||
"martinbirgmeier": "Martin-Birgmeier",
|
||||
"mcpheeslideshow": "McPhee-slideshow",
|
||||
"metamail": "metamail",
|
||||
"minpack": "Minpack",
|
||||
"miros": "MirOS",
|
||||
@@ -809,8 +845,11 @@ var licenseIDs = map[string]string{
|
||||
"mitmodernvariant": "MIT-Modern-Variant",
|
||||
"mitnfa": "MITNFA",
|
||||
"mitopengroup": "MIT-open-group",
|
||||
"mittestregex": "MIT-testregex",
|
||||
"mitwu": "MIT-Wu",
|
||||
"mmixware": "MMIXware",
|
||||
"motosoto": "Motosoto",
|
||||
"mpegssg": "MPEG-SSG",
|
||||
"mpich2": "mpich2",
|
||||
"mpich2.0": "mpich2",
|
||||
"mpich2.0.0": "mpich2",
|
||||
@@ -997,6 +1036,7 @@ var licenseIDs = map[string]string{
|
||||
"ouda1": "O-UDA-1.0",
|
||||
"ouda1.0": "O-UDA-1.0",
|
||||
"ouda1.0.0": "O-UDA-1.0",
|
||||
"padl": "PADL",
|
||||
"parity6": "Parity-6.0.0",
|
||||
"parity6.0": "Parity-6.0.0",
|
||||
"parity6.0.0": "Parity-6.0.0",
|
||||
@@ -1012,6 +1052,7 @@ var licenseIDs = map[string]string{
|
||||
"php3.01": "PHP-3.01",
|
||||
"php3.01.0": "PHP-3.01",
|
||||
"plexus": "Plexus",
|
||||
"pnmstitch": "pnmstitch",
|
||||
"polyformnoncommercial1": "PolyForm-Noncommercial-1.0.0",
|
||||
"polyformnoncommercial1.0": "PolyForm-Noncommercial-1.0.0",
|
||||
"polyformnoncommercial1.0.0": "PolyForm-Noncommercial-1.0.0",
|
||||
@@ -1028,6 +1069,7 @@ var licenseIDs = map[string]string{
|
||||
"python2.0": "Python-2.0",
|
||||
"python2.0.0": "Python-2.0",
|
||||
"python2.0.1": "Python-2.0.1",
|
||||
"pythonldap": "python-ldap",
|
||||
"qhull": "Qhull",
|
||||
"qpl1": "QPL-1.0",
|
||||
"qpl1.0": "QPL-1.0",
|
||||
@@ -1066,6 +1108,7 @@ var licenseIDs = map[string]string{
|
||||
"sgib2": "SGI-B-2.0",
|
||||
"sgib2.0": "SGI-B-2.0",
|
||||
"sgib2.0.0": "SGI-B-2.0",
|
||||
"sgiopengl": "SGI-OpenGL",
|
||||
"sgp4": "SGP4",
|
||||
"sgp4.0": "SGP4",
|
||||
"sgp4.0.0": "SGP4",
|
||||
@@ -1080,11 +1123,13 @@ var licenseIDs = map[string]string{
|
||||
"sissl1": "SISSL-1.2",
|
||||
"sissl1.2": "SISSL-1.2",
|
||||
"sissl1.2.0": "SISSL-1.2",
|
||||
"sl": "SL",
|
||||
"sleepycat": "Sleepycat",
|
||||
"smlnj": "SMLNJ",
|
||||
"smppl": "SMPPL",
|
||||
"snia": "SNIA",
|
||||
"snprintf": "snprintf",
|
||||
"soundex": "Soundex",
|
||||
"spencer86": "Spencer-86",
|
||||
"spencer86.0": "Spencer-86",
|
||||
"spencer86.0.0": "Spencer-86",
|
||||
@@ -1097,6 +1142,7 @@ var licenseIDs = map[string]string{
|
||||
"spl1": "SPL-1.0",
|
||||
"spl1.0": "SPL-1.0",
|
||||
"spl1.0.0": "SPL-1.0",
|
||||
"sshkeyscan": "ssh-keyscan",
|
||||
"sshopenssh": "SSH-OpenSSH",
|
||||
"sshshort": "SSH-short",
|
||||
"sspl1": "SSPL-1.0",
|
||||
@@ -1108,6 +1154,7 @@ var licenseIDs = map[string]string{
|
||||
"sugarcrm1.1.3": "SugarCRM-1.1.3",
|
||||
"sunpro": "SunPro",
|
||||
"swl": "SWL",
|
||||
"swrule": "swrule",
|
||||
"symlinks": "Symlinks",
|
||||
"taprohl1": "TAPR-OHL-1.0",
|
||||
"taprohl1.0": "TAPR-OHL-1.0",
|
||||
@@ -1125,6 +1172,7 @@ var licenseIDs = map[string]string{
|
||||
"tpl1.0": "TPL-1.0",
|
||||
"tpl1.0.0": "TPL-1.0",
|
||||
"ttwl": "TTWL",
|
||||
"ttyp0": "TTYP0",
|
||||
"tuberlin1": "TU-Berlin-1.0",
|
||||
"tuberlin1.0": "TU-Berlin-1.0",
|
||||
"tuberlin1.0.0": "TU-Berlin-1.0",
|
||||
@@ -1135,6 +1183,7 @@ var licenseIDs = map[string]string{
|
||||
"ucl1": "UCL-1.0",
|
||||
"ucl1.0": "UCL-1.0",
|
||||
"ucl1.0.0": "UCL-1.0",
|
||||
"ulem": "ulem",
|
||||
"unicodedfs2015": "Unicode-DFS-2015",
|
||||
"unicodedfs2015.0": "Unicode-DFS-2015",
|
||||
"unicodedfs2015.0.0": "Unicode-DFS-2015",
|
||||
@@ -1147,6 +1196,7 @@ var licenseIDs = map[string]string{
|
||||
"upl1": "UPL-1.0",
|
||||
"upl1.0": "UPL-1.0",
|
||||
"upl1.0.0": "UPL-1.0",
|
||||
"urtrle": "URT-RLE",
|
||||
"vim": "Vim",
|
||||
"vostrom": "VOSTROM",
|
||||
"vsl1": "VSL-1.0",
|
||||
@@ -1196,6 +1246,7 @@ var licenseIDs = map[string]string{
|
||||
"ypl1.1": "YPL-1.1",
|
||||
"ypl1.1.0": "YPL-1.1",
|
||||
"zed": "Zed",
|
||||
"zeeff": "Zeeff",
|
||||
"zend2": "Zend-2.0",
|
||||
"zend2.0": "Zend-2.0",
|
||||
"zend2.0.0": "Zend-2.0",
|
||||
|
||||
@@ -97,7 +97,7 @@ func toCycloneDXAlgorithm(algorithm string) cyclonedx.HashAlgorithm {
|
||||
"sha256": cyclonedx.HashAlgorithm("SHA-256"),
|
||||
}
|
||||
|
||||
return validMap[algorithm]
|
||||
return validMap[strings.ToLower(algorithm)]
|
||||
}
|
||||
|
||||
func decodeExternalReferences(c *cyclonedx.Component, metadata interface{}) {
|
||||
|
||||
@@ -173,3 +173,27 @@ func Test_isValidExternalRef(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_toCycloneDXAlgorithm(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected cyclonedx.HashAlgorithm
|
||||
}{
|
||||
{
|
||||
name: "valid algorithm name in upper case",
|
||||
input: "SHA1",
|
||||
expected: cyclonedx.HashAlgorithm("SHA-1"),
|
||||
},
|
||||
{
|
||||
name: "valid algorithm name in lower case",
|
||||
input: "sha1",
|
||||
expected: cyclonedx.HashAlgorithm("SHA-1"),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
assert.Equal(t, test.expected, toCycloneDXAlgorithm(test.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/spdx/tools-golang/spdx"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cpe
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
@@ -287,6 +288,7 @@ func GetManifestFieldGroupIDs(manifest *pkg.JavaManifest, fields []string) (grou
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Strings(groupIDs)
|
||||
|
||||
return groupIDs
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ var DefaultArtifactIDToGroupID = map[string]string{
|
||||
"ant-weblogic": "org.apache.ant",
|
||||
"ant-xz": "org.apache.ant",
|
||||
"commons-codec": "commons-codec",
|
||||
"commons-logging": "commons-logging", // see e.g. https://mvnrepository.com/artifact/commons-logging/commons-logging/1.1.1
|
||||
"okhttp": "com.squareup.okhttp3",
|
||||
"okio": "com.squareup.okio",
|
||||
"spring": "org.springframework",
|
||||
|
||||
@@ -4,14 +4,21 @@ Package golang provides a concrete Cataloger implementation for go.mod files.
|
||||
package golang
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
var versionCandidateGroups = regexp.MustCompile(`(?P<version>\d+(\.\d+)?(\.\d+)?)(?P<candidate>\w*)`)
|
||||
|
||||
// NewGoModFileCataloger returns a new Go module cataloger object.
|
||||
func NewGoModFileCataloger(opts GoCatalogerOpts) pkg.Cataloger {
|
||||
c := goModCataloger{
|
||||
@@ -47,5 +54,75 @@ func (p *progressingCataloger) Name() string {
|
||||
|
||||
func (p *progressingCataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
defer p.progress.SetCompleted()
|
||||
return p.cataloger.Catalog(resolver)
|
||||
pkgs, relationships, err := p.cataloger.Catalog(resolver)
|
||||
goCompilerPkgs := []pkg.Package{}
|
||||
totalLocations := file.NewLocationSet()
|
||||
for _, goPkg := range pkgs {
|
||||
mValue, ok := goPkg.Metadata.(pkg.GolangBinMetadata)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// go binary packages should only contain a single location
|
||||
for _, location := range goPkg.Locations.ToSlice() {
|
||||
if !totalLocations.Contains(location) {
|
||||
stdLibPkg := newGoStdLib(mValue.GoCompiledVersion, goPkg.Locations)
|
||||
if stdLibPkg != nil {
|
||||
goCompilerPkgs = append(goCompilerPkgs, *stdLibPkg)
|
||||
totalLocations.Add(location)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pkgs = append(pkgs, goCompilerPkgs...)
|
||||
return pkgs, relationships, err
|
||||
}
|
||||
func newGoStdLib(version string, location file.LocationSet) *pkg.Package {
|
||||
stdlibCpe, err := generateStdlibCpe(version)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
goCompilerPkg := &pkg.Package{
|
||||
Name: "stdlib",
|
||||
Version: version,
|
||||
PURL: packageURL("stdlib", strings.TrimPrefix(version, "go")),
|
||||
CPEs: []cpe.CPE{stdlibCpe},
|
||||
Locations: location,
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
GoCompiledVersion: version,
|
||||
},
|
||||
}
|
||||
goCompilerPkg.SetID()
|
||||
|
||||
return goCompilerPkg
|
||||
}
|
||||
|
||||
func generateStdlibCpe(version string) (stdlibCpe cpe.CPE, err error) {
|
||||
// GoCompiledVersion when pulled from a binary is prefixed by go
|
||||
version = strings.TrimPrefix(version, "go")
|
||||
|
||||
// we also need to trim starting from the first +<metadata> to
|
||||
// correctly extract potential rc candidate information for cpe generation
|
||||
// ex: 2.0.0-rc.1+build.123 -> 2.0.0-rc.1; if no + is found then + is returned
|
||||
after, _, found := strings.Cut("+", version)
|
||||
if found {
|
||||
version = after
|
||||
}
|
||||
|
||||
// extracting <version> and <candidate>
|
||||
// https://regex101.com/r/985GsI/1
|
||||
captureGroups := internal.MatchNamedCaptureGroups(versionCandidateGroups, version)
|
||||
vr, ok := captureGroups["version"]
|
||||
if !ok || vr == "" {
|
||||
return stdlibCpe, fmt.Errorf("could not match candidate version for: %s", version)
|
||||
}
|
||||
|
||||
cpeString := fmt.Sprintf("cpe:2.3:a:golang:go:%s:-:*:*:*:*:*:*", captureGroups["version"])
|
||||
if candidate, ok := captureGroups["candidate"]; ok && candidate != "" {
|
||||
cpeString = fmt.Sprintf("cpe:2.3:a:golang:go:%s:%s:*:*:*:*:*:*", vr, candidate)
|
||||
}
|
||||
|
||||
return cpe.New(cpeString)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package golang
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
)
|
||||
|
||||
@@ -56,3 +59,30 @@ func Test_Binary_Cataloger_Globs(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Binary_Cataloger_Stdlib_Cpe(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
candidate string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "generateStdlibCpe generates a cpe with a - for a major version",
|
||||
candidate: "go1.21.0",
|
||||
want: "cpe:2.3:a:golang:go:1.21.0:-:*:*:*:*:*:*",
|
||||
},
|
||||
{
|
||||
name: "generateStdlibCpe generates a cpe with an rc candidate for a major rc version",
|
||||
candidate: "go1.21rc2",
|
||||
want: "cpe:2.3:a:golang:go:1.21:rc2:*:*:*:*:*:*",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got, err := generateStdlibCpe(tc.candidate)
|
||||
assert.NoError(t, err, "expected no err; got %v", err)
|
||||
assert.Equal(t, cpe.String(got), tc.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ func (c *goBinaryCataloger) parseGoBinary(resolver file.Resolver, _ *generic.Env
|
||||
for _, mod := range mods {
|
||||
pkgs = append(pkgs, c.buildGoPkgInfo(resolver, reader.Location, mod, mod.arch)...)
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -171,19 +171,14 @@ func (j *archiveParser) discoverMainPackage() (*pkg.Package, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
archiveCloser, err := os.Open(j.archivePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open archive path (%s): %w", j.archivePath, err)
|
||||
}
|
||||
defer archiveCloser.Close()
|
||||
|
||||
// grab and assign digest for the entire archive
|
||||
digests, err := intFile.NewDigestsFromFile(archiveCloser, javaArchiveHashes)
|
||||
digests, err := getDigestsFromArchive(j.archivePath)
|
||||
if err != nil {
|
||||
log.Warnf("failed to create digest for file=%q: %+v", j.archivePath, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// we use j.location because we want to associate the license declaration with where we discovered the contents in the manifest
|
||||
// TODO: when we support locations of paths within archives we should start passing the specific manifest location object instead of the top jar
|
||||
licenses := pkg.NewLicensesFromLocation(j.location, selectLicenses(manifest)...)
|
||||
/*
|
||||
We should name and version from, in this order:
|
||||
@@ -192,13 +187,20 @@ func (j *archiveParser) discoverMainPackage() (*pkg.Package, error) {
|
||||
3. manifest
|
||||
4. filename
|
||||
*/
|
||||
name, version := j.guessMainPackageNameAndVersionFromPomInfo()
|
||||
name, version, pomLicenses := j.guessMainPackageNameAndVersionFromPomInfo()
|
||||
if name == "" {
|
||||
name = selectName(manifest, j.fileInfo)
|
||||
}
|
||||
if version == "" {
|
||||
version = selectVersion(manifest, j.fileInfo)
|
||||
}
|
||||
if len(licenses) == 0 {
|
||||
// Today we don't have a way to distinguish between licenses from the manifest and licenses from the pom.xml
|
||||
// until the file.Location object can support sub-paths (i.e. paths within archives, recursively; issue https://github.com/anchore/syft/issues/2211).
|
||||
// Until then it's less confusing to use the licenses from the pom.xml only if the manifest did not list any.
|
||||
licenses = append(licenses, pomLicenses...)
|
||||
}
|
||||
|
||||
return &pkg.Package{
|
||||
// TODO: maybe select name should just have a pom properties in it?
|
||||
Name: name,
|
||||
@@ -218,11 +220,16 @@ func (j *archiveParser) discoverMainPackage() (*pkg.Package, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (j *archiveParser) guessMainPackageNameAndVersionFromPomInfo() (string, string) {
|
||||
type parsedPomProject struct {
|
||||
*pkg.PomProject
|
||||
Licenses []pkg.License
|
||||
}
|
||||
|
||||
func (j *archiveParser) guessMainPackageNameAndVersionFromPomInfo() (name, version string, licenses []pkg.License) {
|
||||
pomPropertyMatches := j.fileManifest.GlobMatch(pomPropertiesGlob)
|
||||
pomMatches := j.fileManifest.GlobMatch(pomXMLGlob)
|
||||
var pomPropertiesObject pkg.PomProperties
|
||||
var pomProjectObject pkg.PomProject
|
||||
var pomProjectObject parsedPomProject
|
||||
if len(pomPropertyMatches) == 1 || len(pomMatches) == 1 {
|
||||
// we have exactly 1 pom.properties or pom.xml in the archive; assume it represents the
|
||||
// package we're scanning if the names seem like a plausible match
|
||||
@@ -238,15 +245,15 @@ func (j *archiveParser) guessMainPackageNameAndVersionFromPomInfo() (string, str
|
||||
}
|
||||
}
|
||||
}
|
||||
name := pomPropertiesObject.ArtifactID
|
||||
if name == "" {
|
||||
name = pomPropertiesObject.ArtifactID
|
||||
if name == "" && pomProjectObject.PomProject != nil {
|
||||
name = pomProjectObject.ArtifactID
|
||||
}
|
||||
version := pomPropertiesObject.Version
|
||||
if version == "" {
|
||||
version = pomPropertiesObject.Version
|
||||
if version == "" && pomProjectObject.PomProject != nil {
|
||||
version = pomProjectObject.Version
|
||||
}
|
||||
return name, version
|
||||
return name, version, pomProjectObject.Licenses
|
||||
}
|
||||
|
||||
// discoverPkgsFromAllMavenFiles parses Maven POM properties/xml for a given
|
||||
@@ -273,7 +280,7 @@ func (j *archiveParser) discoverPkgsFromAllMavenFiles(parentPkg *pkg.Package) ([
|
||||
}
|
||||
|
||||
for parentPath, propertiesObj := range properties {
|
||||
var pomProject *pkg.PomProject
|
||||
var pomProject *parsedPomProject
|
||||
if proj, exists := projects[parentPath]; exists {
|
||||
pomProject = &proj
|
||||
}
|
||||
@@ -287,6 +294,22 @@ func (j *archiveParser) discoverPkgsFromAllMavenFiles(parentPkg *pkg.Package) ([
|
||||
return pkgs, nil
|
||||
}
|
||||
|
||||
func getDigestsFromArchive(archivePath string) ([]file.Digest, error) {
|
||||
archiveCloser, err := os.Open(archivePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open archive path (%s): %w", archivePath, err)
|
||||
}
|
||||
defer archiveCloser.Close()
|
||||
|
||||
// grab and assign digest for the entire archive
|
||||
digests, err := intFile.NewDigestsFromFile(archiveCloser, javaArchiveHashes)
|
||||
if err != nil {
|
||||
log.Warnf("failed to create digest for file=%q: %+v", archivePath, err)
|
||||
}
|
||||
|
||||
return digests, nil
|
||||
}
|
||||
|
||||
func (j *archiveParser) discoverPkgsFromNestedArchives(parentPkg *pkg.Package) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
// we know that all java archives are zip formatted files, so we can use the shared zip helper
|
||||
return discoverPkgsFromZip(j.location, j.archivePath, j.contentPath, j.fileManifest, parentPkg)
|
||||
@@ -388,15 +411,16 @@ func pomPropertiesByParentPath(archivePath string, location file.Location, extra
|
||||
return propertiesByParentPath, nil
|
||||
}
|
||||
|
||||
func pomProjectByParentPath(archivePath string, location file.Location, extractPaths []string) (map[string]pkg.PomProject, error) {
|
||||
func pomProjectByParentPath(archivePath string, location file.Location, extractPaths []string) (map[string]parsedPomProject, error) {
|
||||
contentsOfMavenProjectFiles, err := intFile.ContentsFromZip(archivePath, extractPaths...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to extract maven files: %w", err)
|
||||
}
|
||||
|
||||
projectByParentPath := make(map[string]pkg.PomProject)
|
||||
projectByParentPath := make(map[string]parsedPomProject)
|
||||
for filePath, fileContents := range contentsOfMavenProjectFiles {
|
||||
pomProject, err := parsePomXMLProject(filePath, strings.NewReader(fileContents))
|
||||
// TODO: when we support locations of paths within archives we should start passing the specific pom.xml location object instead of the top jar
|
||||
pomProject, err := parsePomXMLProject(filePath, strings.NewReader(fileContents), location)
|
||||
if err != nil {
|
||||
log.WithFields("contents-path", filePath, "location", location.AccessPath()).Warnf("failed to parse pom.xml: %+v", err)
|
||||
continue
|
||||
@@ -418,7 +442,7 @@ func pomProjectByParentPath(archivePath string, location file.Location, extractP
|
||||
|
||||
// newPackageFromMavenData processes a single Maven POM properties for a given parent package, returning all listed Java packages found and
|
||||
// associating each discovered package to the given parent package. Note the pom.xml is optional, the pom.properties is not.
|
||||
func newPackageFromMavenData(pomProperties pkg.PomProperties, pomProject *pkg.PomProject, parentPkg *pkg.Package, location file.Location) *pkg.Package {
|
||||
func newPackageFromMavenData(pomProperties pkg.PomProperties, parsedPomProject *parsedPomProject, parentPkg *pkg.Package, location file.Location) *pkg.Package {
|
||||
// keep the artifact name within the virtual path if this package does not match the parent package
|
||||
vPathSuffix := ""
|
||||
groupID := ""
|
||||
@@ -440,20 +464,27 @@ func newPackageFromMavenData(pomProperties pkg.PomProperties, pomProject *pkg.Po
|
||||
}
|
||||
virtualPath := location.AccessPath() + vPathSuffix
|
||||
|
||||
// discovered props = new package
|
||||
var pkgPomProject *pkg.PomProject
|
||||
licenses := make([]pkg.License, 0)
|
||||
if parsedPomProject != nil {
|
||||
pkgPomProject = parsedPomProject.PomProject
|
||||
licenses = append(licenses, parsedPomProject.Licenses...)
|
||||
}
|
||||
|
||||
p := pkg.Package{
|
||||
Name: pomProperties.ArtifactID,
|
||||
Version: pomProperties.Version,
|
||||
Locations: file.NewLocationSet(
|
||||
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
Licenses: pkg.NewLicenseSet(licenses...),
|
||||
Language: pkg.Java,
|
||||
Type: pomProperties.PkgTypeIndicated(),
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
Metadata: pkg.JavaMetadata{
|
||||
VirtualPath: virtualPath,
|
||||
PomProperties: &pomProperties,
|
||||
PomProject: pomProject,
|
||||
PomProject: pkgPomProject,
|
||||
Parent: parentPkg,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -17,6 +16,7 @@ import (
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/license"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
)
|
||||
@@ -83,11 +83,13 @@ func generateJavaBuildFixture(t *testing.T, fixturePath string) {
|
||||
|
||||
func TestParseJar(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
expected map[string]pkg.Package
|
||||
ignoreExtras []string
|
||||
}{
|
||||
{
|
||||
name: "example-jenkins-plugin",
|
||||
fixture: "test-fixtures/java-builds/packages/example-jenkins-plugin.hpi",
|
||||
ignoreExtras: []string{
|
||||
"Plugin-Version", // has dynamic date
|
||||
@@ -146,6 +148,7 @@ func TestParseJar(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "example-java-app-gradle",
|
||||
fixture: "test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar",
|
||||
expected: map[string]pkg.Package{
|
||||
"example-java-app-gradle": {
|
||||
@@ -172,6 +175,16 @@ func TestParseJar(t *testing.T) {
|
||||
Language: pkg.Java,
|
||||
Type: pkg.JavaPkg,
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromFields(
|
||||
"Apache 2",
|
||||
"http://www.apache.org/licenses/LICENSE-2.0.txt",
|
||||
func() *file.Location {
|
||||
l := file.NewLocation("test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar")
|
||||
return &l
|
||||
}(),
|
||||
),
|
||||
),
|
||||
Metadata: pkg.JavaMetadata{
|
||||
// ensure that nested packages with different names than that of the parent are appended as
|
||||
// a suffix on the virtual path with a colon separator between group name and artifact name
|
||||
@@ -196,6 +209,7 @@ func TestParseJar(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "example-java-app-maven",
|
||||
fixture: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
|
||||
ignoreExtras: []string{
|
||||
"Build-Jdk", // can't guarantee the JDK used at build time
|
||||
@@ -231,9 +245,19 @@ func TestParseJar(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"joda-time": {
|
||||
Name: "joda-time",
|
||||
Version: "2.9.2",
|
||||
PURL: "pkg:maven/joda-time/joda-time@2.9.2",
|
||||
Name: "joda-time",
|
||||
Version: "2.9.2",
|
||||
PURL: "pkg:maven/joda-time/joda-time@2.9.2",
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromFields(
|
||||
"Apache 2",
|
||||
"http://www.apache.org/licenses/LICENSE-2.0.txt",
|
||||
func() *file.Location {
|
||||
l := file.NewLocation("test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar")
|
||||
return &l
|
||||
}(),
|
||||
),
|
||||
),
|
||||
Language: pkg.Java,
|
||||
Type: pkg.JavaPkg,
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
@@ -263,7 +287,7 @@ func TestParseJar(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(path.Base(test.fixture), func(t *testing.T) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
generateJavaBuildFixture(t, test.fixture)
|
||||
|
||||
@@ -618,7 +642,7 @@ func Test_newPackageFromMavenData(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
props pkg.PomProperties
|
||||
project *pkg.PomProject
|
||||
project *parsedPomProject
|
||||
parent *pkg.Package
|
||||
expectedParent pkg.Package
|
||||
expectedPackage *pkg.Package
|
||||
@@ -687,18 +711,29 @@ func Test_newPackageFromMavenData(t *testing.T) {
|
||||
ArtifactID: "some-artifact-id",
|
||||
Version: "1.0",
|
||||
},
|
||||
project: &pkg.PomProject{
|
||||
Parent: &pkg.PomParent{
|
||||
GroupID: "some-parent-group-id",
|
||||
ArtifactID: "some-parent-artifact-id",
|
||||
Version: "1.0-parent",
|
||||
project: &parsedPomProject{
|
||||
PomProject: &pkg.PomProject{
|
||||
Parent: &pkg.PomParent{
|
||||
GroupID: "some-parent-group-id",
|
||||
ArtifactID: "some-parent-artifact-id",
|
||||
Version: "1.0-parent",
|
||||
},
|
||||
Name: "some-name",
|
||||
GroupID: "some-group-id",
|
||||
ArtifactID: "some-artifact-id",
|
||||
Version: "1.0",
|
||||
Description: "desc",
|
||||
URL: "aweso.me",
|
||||
},
|
||||
Licenses: []pkg.License{
|
||||
{
|
||||
Value: "MIT",
|
||||
SPDXExpression: "MIT",
|
||||
Type: license.Declared,
|
||||
URLs: internal.NewStringSet("https://opensource.org/licenses/MIT"),
|
||||
Locations: file.NewLocationSet(file.NewLocation("some-license-path")),
|
||||
},
|
||||
},
|
||||
Name: "some-name",
|
||||
GroupID: "some-group-id",
|
||||
ArtifactID: "some-artifact-id",
|
||||
Version: "1.0",
|
||||
Description: "desc",
|
||||
URL: "aweso.me",
|
||||
},
|
||||
parent: &pkg.Package{
|
||||
Name: "some-parent-name",
|
||||
@@ -727,6 +762,15 @@ func Test_newPackageFromMavenData(t *testing.T) {
|
||||
Language: pkg.Java,
|
||||
Type: pkg.JavaPkg,
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.License{
|
||||
Value: "MIT",
|
||||
SPDXExpression: "MIT",
|
||||
Type: license.Declared,
|
||||
URLs: internal.NewStringSet("https://opensource.org/licenses/MIT"),
|
||||
Locations: file.NewLocationSet(file.NewLocation("some-license-path")),
|
||||
},
|
||||
),
|
||||
Metadata: pkg.JavaMetadata{
|
||||
VirtualPath: virtualPath + ":" + "some-group-id" + ":" + "some-artifact-id",
|
||||
PomProperties: &pkg.PomProperties{
|
||||
|
||||
@@ -49,28 +49,51 @@ func parserPomXML(_ file.Resolver, _ *generic.Environment, reader file.LocationR
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
func parsePomXMLProject(path string, reader io.Reader) (*pkg.PomProject, error) {
|
||||
func parsePomXMLProject(path string, reader io.Reader, location file.Location) (*parsedPomProject, error) {
|
||||
project, err := decodePomXML(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newPomProject(path, project), nil
|
||||
return newPomProject(path, project, location), nil
|
||||
}
|
||||
|
||||
func newPomProject(path string, p gopom.Project) *pkg.PomProject {
|
||||
func newPomProject(path string, p gopom.Project, location file.Location) *parsedPomProject {
|
||||
artifactID := safeString(p.ArtifactID)
|
||||
name := safeString(p.Name)
|
||||
projectURL := safeString(p.URL)
|
||||
|
||||
var licenses []pkg.License
|
||||
if p.Licenses != nil {
|
||||
for _, license := range *p.Licenses {
|
||||
var licenseName, licenseURL string
|
||||
if license.Name != nil {
|
||||
licenseName = *license.Name
|
||||
}
|
||||
if license.URL != nil {
|
||||
licenseURL = *license.URL
|
||||
}
|
||||
|
||||
if licenseName == "" && licenseURL == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
licenses = append(licenses, pkg.NewLicenseFromFields(licenseName, licenseURL, &location))
|
||||
}
|
||||
}
|
||||
|
||||
log.WithFields("path", path, "artifactID", artifactID, "name", name, "projectURL", projectURL).Trace("parsing pom.xml")
|
||||
return &pkg.PomProject{
|
||||
Path: path,
|
||||
Parent: pomParent(p, p.Parent),
|
||||
GroupID: resolveProperty(p, p.GroupID, "groupId"),
|
||||
ArtifactID: artifactID,
|
||||
Version: resolveProperty(p, p.Version, "version"),
|
||||
Name: name,
|
||||
Description: cleanDescription(p.Description),
|
||||
URL: projectURL,
|
||||
return &parsedPomProject{
|
||||
PomProject: &pkg.PomProject{
|
||||
Path: path,
|
||||
Parent: pomParent(p, p.Parent),
|
||||
GroupID: resolveProperty(p, p.GroupID, "groupId"),
|
||||
ArtifactID: artifactID,
|
||||
Version: resolveProperty(p, p.Version, "version"),
|
||||
Name: name,
|
||||
Description: cleanDescription(p.Description),
|
||||
URL: projectURL,
|
||||
},
|
||||
Licenses: licenses,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/vifraa/gopom"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/license"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
)
|
||||
@@ -293,33 +295,79 @@ func Test_parseCommonsTextPomXMLProject(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_parsePomXMLProject(t *testing.T) {
|
||||
// TODO: ideally we would have the path to the contained pom.xml, not the jar
|
||||
jarLocation := file.NewLocation("path/to/archive.jar")
|
||||
tests := []struct {
|
||||
expected pkg.PomProject
|
||||
name string
|
||||
expected parsedPomProject
|
||||
}{
|
||||
{
|
||||
expected: pkg.PomProject{
|
||||
Path: "test-fixtures/pom/commons-codec.pom.xml",
|
||||
Parent: &pkg.PomParent{
|
||||
GroupID: "org.apache.commons",
|
||||
ArtifactID: "commons-parent",
|
||||
Version: "42",
|
||||
name: "go case",
|
||||
expected: parsedPomProject{
|
||||
PomProject: &pkg.PomProject{
|
||||
Path: "test-fixtures/pom/commons-codec.pom.xml",
|
||||
Parent: &pkg.PomParent{
|
||||
GroupID: "org.apache.commons",
|
||||
ArtifactID: "commons-parent",
|
||||
Version: "42",
|
||||
},
|
||||
GroupID: "commons-codec",
|
||||
ArtifactID: "commons-codec",
|
||||
Version: "1.11",
|
||||
Name: "Apache Commons Codec",
|
||||
Description: "The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal. In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.",
|
||||
URL: "http://commons.apache.org/proper/commons-codec/",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with license data",
|
||||
expected: parsedPomProject{
|
||||
PomProject: &pkg.PomProject{
|
||||
Path: "test-fixtures/pom/neo4j-license-maven-plugin.pom.xml",
|
||||
Parent: &pkg.PomParent{
|
||||
GroupID: "org.sonatype.oss",
|
||||
ArtifactID: "oss-parent",
|
||||
Version: "7",
|
||||
},
|
||||
GroupID: "org.neo4j.build.plugins",
|
||||
ArtifactID: "license-maven-plugin",
|
||||
Version: "4-SNAPSHOT",
|
||||
Name: "${project.artifactId}", // TODO: this is not an ideal answer
|
||||
Description: "Maven 2 plugin to check and update license headers in source files",
|
||||
URL: "http://components.neo4j.org/${project.artifactId}/${project.version}", // TODO: this is not an ideal answer
|
||||
},
|
||||
Licenses: []pkg.License{
|
||||
{
|
||||
Value: "The Apache Software License, Version 2.0",
|
||||
SPDXExpression: "", // TODO: ideally we would parse this title to get Apache-2.0 (created issue #2210 https://github.com/anchore/syft/issues/2210)
|
||||
Type: license.Declared,
|
||||
URLs: internal.NewStringSet("http://www.apache.org/licenses/LICENSE-2.0.txt"),
|
||||
Locations: file.NewLocationSet(jarLocation),
|
||||
},
|
||||
{
|
||||
Value: "MIT",
|
||||
SPDXExpression: "MIT",
|
||||
Type: license.Declared,
|
||||
URLs: internal.NewStringSet(),
|
||||
Locations: file.NewLocationSet(jarLocation),
|
||||
},
|
||||
{
|
||||
Type: license.Declared,
|
||||
URLs: internal.NewStringSet("https://opensource.org/license/unlicense/"),
|
||||
Locations: file.NewLocationSet(jarLocation),
|
||||
},
|
||||
},
|
||||
GroupID: "commons-codec",
|
||||
ArtifactID: "commons-codec",
|
||||
Version: "1.11",
|
||||
Name: "Apache Commons Codec",
|
||||
Description: "The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal. In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.",
|
||||
URL: "http://commons.apache.org/proper/commons-codec/",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.expected.Path, func(t *testing.T) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fixture, err := os.Open(test.expected.Path)
|
||||
assert.NoError(t, err)
|
||||
|
||||
actual, err := parsePomXMLProject(fixture.Name(), fixture)
|
||||
actual, err := parsePomXMLProject(fixture.Name(), fixture, jarLocation)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, &test.expected, actual)
|
||||
|
||||
@@ -0,0 +1,459 @@
|
||||
<!-- sourced from https://github.com/neo4j/license-maven-plugin/blob/3/pom.xml -->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.sonatype.oss</groupId>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>7</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
<groupId>org.neo4j.build.plugins</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>å
|
||||
<version>4-SNAPSHOT</version>
|
||||
<packaging>maven-plugin</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>Maven 2 plugin to check and update license headers in source files</description>
|
||||
<url>http://components.neo4j.org/${project.artifactId}/${project.version}</url>
|
||||
<inceptionYear>2008</inceptionYear>
|
||||
|
||||
<!--
|
||||
Properties
|
||||
-->
|
||||
|
||||
<properties>
|
||||
<jdk>1.6</jdk>
|
||||
<jdk.version>1.6</jdk.version>
|
||||
</properties>
|
||||
|
||||
<!--
|
||||
Versioning system
|
||||
-->
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/neo4j/license-maven-plugin.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:neo4j/license-maven-plugin.git</developerConnection>
|
||||
<url>https://github.com/neo4j/license-maven-plugin</url>
|
||||
</scm>
|
||||
|
||||
<!--
|
||||
Project settings
|
||||
-->
|
||||
|
||||
<organization>
|
||||
<name>Mathieu Carbou</name>
|
||||
<url>http://mathieu.carbou.free.fr/</url>
|
||||
</organization>
|
||||
|
||||
<licenses>
|
||||
<!-- this has been modified for the purposes of a syft test -->
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
<license>
|
||||
<name>MIT</name>
|
||||
</license>
|
||||
<license>
|
||||
<url>https://opensource.org/license/unlicense/</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>mimilowns</id>
|
||||
<name>Cédric</name>
|
||||
<email>mimilowns@gmail.com</email>
|
||||
<timezone>+1</timezone>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>mathieu.carbou</id>
|
||||
<name>Mathieu Carbou</name>
|
||||
<email>mathieu.carbou@gmail.com</email>
|
||||
<organization>Mycila</organization>
|
||||
<organizationUrl>http://mathieu.carbou.free.fr/</organizationUrl>
|
||||
<timezone>-5</timezone>
|
||||
<roles>
|
||||
<role>project owner</role>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<issueManagement>
|
||||
<system>Google Code</system>
|
||||
<url>http://code.google.com/p/${project.artifactId}/issues/list</url>
|
||||
</issueManagement>
|
||||
|
||||
<ciManagement />
|
||||
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>maven-license-plugin-announce</name>
|
||||
<subscribe>maven-license-plugin-announce-subscribe@googlegroups.com</subscribe>
|
||||
<unsubscribe>maven-license-plugin-announce-unsubscribe@googlegroups.com</unsubscribe>
|
||||
<archive>http://groups.google.com/group/maven-license-plugin-announce</archive>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>maven-license-plugin-codesite</name>
|
||||
<subscribe>maven-license-plugin-codesite-subscribe@googlegroups.com</subscribe>
|
||||
<unsubscribe>maven-license-plugin-codesite-unsubscribe@googlegroups.com</unsubscribe>
|
||||
<archive>http://groups.google.com/group/maven-license-plugin-codesite</archive>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
|
||||
<!--
|
||||
Distributions
|
||||
-->
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>sonatype-nexus-staging</id>
|
||||
<name>Nexus Release Repository</name>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>snapshots@m2.neo4j.org</id>
|
||||
<name>snapshots@m2.neo4j.org</name>
|
||||
<url>http://m2.neo4j.org/content/repositories/snapshots</url>
|
||||
</snapshotRepository>
|
||||
<site>
|
||||
<id>neo4j-site</id>
|
||||
<url>scpexe://components.neo4j.org/home/neo/components/${project.artifactId}/${project.version}</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
|
||||
<!--
|
||||
BUILD
|
||||
-->
|
||||
|
||||
<build>
|
||||
<extensions>
|
||||
<extension>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-webdav</artifactId>
|
||||
<version>1.0-beta-2</version>
|
||||
</extension>
|
||||
</extensions>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-ipojo-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.mycila.maven-license-plugin</groupId>
|
||||
<artifactId>maven-license-plugin</artifactId>
|
||||
<version>1.8.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.1.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>2.4.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-invoker-plugin</artifactId>
|
||||
<version>1.5</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>1.3.3</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.2-beta-5</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>2.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<configuration>
|
||||
<keyname>Neo Technology Build Server</keyname>
|
||||
<useAgent>true</useAgent>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<!-- for maven plugins -->
|
||||
<plugin>
|
||||
<artifactId>maven-plugin-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<configuration>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<directory>.clover</directory>
|
||||
</fileset>
|
||||
<fileset>
|
||||
<directory>test-output</directory>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- compilation -->
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${jdk}</source>
|
||||
<target>${jdk}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- testing -->
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
<!-- packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-remote-resources-plugin</artifactId>
|
||||
<version>1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>process</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resourceBundles>
|
||||
<resourceBundle>org.apache:apache-jar-resource-bundle:1.3</resourceBundle>
|
||||
</resourceBundles>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>project</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- releasing -->
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<updateReleaseInfo>true</updateReleaseInfo>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
</plugin>
|
||||
<!-- documentation -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.mycila.maven-license-plugin</groupId>
|
||||
<artifactId>maven-license-plugin</artifactId>
|
||||
<version>1.9.0</version>
|
||||
<configuration>
|
||||
<header>${basedir}/src/etc/header.txt</header>
|
||||
<failIfMissing>true</failIfMissing>
|
||||
<excludes>
|
||||
<exclude>.gitignore</exclude>
|
||||
<exclude>LICENSE.txt</exclude>
|
||||
<exclude>NOTICE.txt</exclude>
|
||||
<exclude>src/test/data/**</exclude>
|
||||
<exclude>src/test/integration/**</exclude>
|
||||
<exclude>src/test/resources/**</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- automatically handle it tests -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<configuration>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<directory>it</directory>
|
||||
<includes>
|
||||
<include>target/**</include>
|
||||
<include>*/target/**</include>
|
||||
</includes>
|
||||
</fileset>
|
||||
<fileset>
|
||||
<directory>target</directory>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<inherited>true</inherited>
|
||||
<artifactId>maven-invoker-plugin</artifactId>
|
||||
<configuration>
|
||||
<projectsDirectory>it</projectsDirectory>
|
||||
<showErrors>true</showErrors>
|
||||
<streamLogs>true</streamLogs>
|
||||
<skipInstallation>${ittest.skip}</skipInstallation>
|
||||
<skipInvocation>${ittest.skip}</skipInvocation>
|
||||
<properties>
|
||||
<target.version>${target.version}</target.version>
|
||||
</properties>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<pomIncludes>
|
||||
<pomInclude>**/pom.xml</pomInclude>
|
||||
</pomIncludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>integration-test</id>
|
||||
<goals>
|
||||
<goal>install</goal>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<!--
|
||||
LIBS
|
||||
-->
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-plugin-api</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mycila.xmltool</groupId>
|
||||
<artifactId>xmltool</artifactId>
|
||||
<version>3.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-project</artifactId>
|
||||
<version>3.0-alpha-2</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-utils</artifactId>
|
||||
<version>2.0.5</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- testing -->
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<version>5.7</version>
|
||||
<classifier>jdk15</classifier>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-embedder</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugin-testing</groupId>
|
||||
<artifactId>maven-plugin-testing-harness</artifactId>
|
||||
<version>2.0-alpha-1</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+19
-15
@@ -60,24 +60,17 @@ func (l Licenses) Swap(i, j int) {
|
||||
}
|
||||
|
||||
func NewLicense(value string) License {
|
||||
spdxExpression, err := license.ParseExpression(value)
|
||||
if err != nil {
|
||||
log.Trace("unable to parse license expression for %q: %w", value, err)
|
||||
}
|
||||
|
||||
return License{
|
||||
Value: value,
|
||||
SPDXExpression: spdxExpression,
|
||||
Type: license.Declared,
|
||||
URLs: internal.NewStringSet(),
|
||||
Locations: file.NewLocationSet(),
|
||||
}
|
||||
return NewLicenseFromType(value, license.Declared)
|
||||
}
|
||||
|
||||
func NewLicenseFromType(value string, t license.Type) License {
|
||||
spdxExpression, err := license.ParseExpression(value)
|
||||
if err != nil {
|
||||
log.Trace("unable to parse license expression: %w", err)
|
||||
var spdxExpression string
|
||||
if value != "" {
|
||||
var err error
|
||||
spdxExpression, err = license.ParseExpression(value)
|
||||
if err != nil {
|
||||
log.Trace("unable to parse license expression: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return License{
|
||||
@@ -124,6 +117,17 @@ func NewLicenseFromURLs(value string, urls ...string) License {
|
||||
return l
|
||||
}
|
||||
|
||||
func NewLicenseFromFields(value, url string, location *file.Location) License {
|
||||
l := NewLicense(value)
|
||||
if location != nil {
|
||||
l.Locations.Add(*location)
|
||||
}
|
||||
if url != "" {
|
||||
l.URLs.Add(url)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// this is a bit of a hack to not infinitely recurse when hashing a license
|
||||
func (s License) Merge(l License) (*License, error) {
|
||||
sHash, err := artifact.IDByHash(s)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/bmatcuk/doublestar/v4"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
"github.com/anchore/stereoscope"
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func TestGolangCompilerDetection(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
image string
|
||||
expectedCompilers []string
|
||||
expectedCPE []cpe.CPE
|
||||
expectedPURL []string
|
||||
}{
|
||||
{
|
||||
name: "syft can detect a single golang compiler given the golang base image",
|
||||
image: "image-golang-compiler",
|
||||
expectedCompilers: []string{"go1.18.10"},
|
||||
expectedCPE: []cpe.CPE{cpe.Must("cpe:2.3:a:golang:go:1.18.10:-:*:*:*:*:*:*")},
|
||||
expectedPURL: []string{"pkg:golang/stdlib@1.18.10"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
sbom, _ := catalogFixtureImage(t, tt.image, source.SquashedScope, nil)
|
||||
packages := sbom.Artifacts.Packages.PackagesByName("stdlib")
|
||||
|
||||
foundCompilerVersions := make(map[string]struct{})
|
||||
foundCPE := make(map[cpe.CPE]struct{})
|
||||
foundPURL := make(map[string]struct{})
|
||||
|
||||
for _, pkg := range packages {
|
||||
foundCompilerVersions[pkg.Version] = struct{}{}
|
||||
foundPURL[pkg.PURL] = struct{}{}
|
||||
for _, cpe := range pkg.CPEs {
|
||||
foundCPE[cpe] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
for _, expectedCompiler := range tt.expectedCompilers {
|
||||
if _, ok := foundCompilerVersions[expectedCompiler]; !ok {
|
||||
t.Fatalf("expected %s version; not found in found compilers: %v", expectedCompiler, foundCompilerVersions)
|
||||
}
|
||||
}
|
||||
|
||||
for _, expectedPURL := range tt.expectedPURL {
|
||||
if _, ok := foundPURL[expectedPURL]; !ok {
|
||||
t.Fatalf("expected %s purl; not found in found purl: %v", expectedPURL, expectedPURLs)
|
||||
}
|
||||
}
|
||||
|
||||
for _, expectedCPE := range tt.expectedCPE {
|
||||
if _, ok := foundCPE[expectedCPE]; !ok {
|
||||
t.Fatalf("expected %s version; not found in found cpe: %v", expectedCPE, expectedCPE)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -76,9 +76,9 @@ var expectedPURLs = map[string]string{
|
||||
"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/org.apache.commons.logging/commons-logging@1.0.4",
|
||||
"commons-logging@1.1": "pkg:maven/org.apache.commons.logging/commons-logging@1.1",
|
||||
"commons-logging@1.1.1": "pkg:maven/commons-logging/commons-logging@1.1.1",
|
||||
"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",
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
|
||||
func TestRegressionGoArchDiscovery(t *testing.T) {
|
||||
const (
|
||||
expectedELFPkg = 4
|
||||
expectedWINPkg = 4
|
||||
expectedMACOSPkg = 4
|
||||
expectedELFPkg = 5
|
||||
expectedWINPkg = 5
|
||||
expectedMACOSPkg = 5
|
||||
)
|
||||
// This is a regression test to make sure the way we detect go binary packages
|
||||
// stays consistent and reproducible as the tool chain evolves
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
FROM golang:1.18.10-alpine
|
||||
Reference in New Issue
Block a user