mirror of
https://github.com/anchore/syft.git
synced 2026-10-26 03:52:22 +01:00
Compare commits
+5
-5
@@ -26,7 +26,7 @@ tools:
|
||||
# used for linting
|
||||
- name: golangci-lint
|
||||
version:
|
||||
want: v1.64.8
|
||||
want: v2.1.5
|
||||
method: github-release
|
||||
with:
|
||||
repo: golangci/golangci-lint
|
||||
@@ -42,7 +42,7 @@ tools:
|
||||
# used for signing the checksums file at release
|
||||
- name: cosign
|
||||
version:
|
||||
want: v2.4.3
|
||||
want: v2.5.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: sigstore/cosign
|
||||
@@ -58,7 +58,7 @@ tools:
|
||||
# used to release all artifacts
|
||||
- name: goreleaser
|
||||
version:
|
||||
want: v2.8.1
|
||||
want: v2.8.2
|
||||
method: github-release
|
||||
with:
|
||||
repo: goreleaser/goreleaser
|
||||
@@ -103,7 +103,7 @@ tools:
|
||||
# used for running all local and CI tasks
|
||||
- name: task
|
||||
version:
|
||||
want: v3.42.1
|
||||
want: v3.43.2
|
||||
method: github-release
|
||||
with:
|
||||
repo: go-task/task
|
||||
@@ -111,7 +111,7 @@ tools:
|
||||
# used for triggering a release
|
||||
- name: gh
|
||||
version:
|
||||
want: v2.69.0
|
||||
want: v2.71.2
|
||||
method: github-release
|
||||
with:
|
||||
repo: cli/cli
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
path: test/results/**/*
|
||||
|
||||
- name: Update PR benchmark results comment
|
||||
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 #v2.9.1
|
||||
uses: marocchino/sticky-pull-request-comment@67d0dec7b07ed060a405f9b2a64b8ab319fdd7db #v2.9.2
|
||||
continue-on-error: true
|
||||
with:
|
||||
header: benchmark
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@1b549b9259bda1cb5ddde3b41741a82a2d15a841 #v3.28.13
|
||||
uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 #v3.28.16
|
||||
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@1b549b9259bda1cb5ddde3b41741a82a2d15a841 #v3.28.13
|
||||
uses: github/codeql-action/autobuild@28deaeda66b76a05916b6923827895f2b14ab387 #v3.28.16
|
||||
|
||||
# ℹ️ 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@1b549b9259bda1cb5ddde3b41741a82a2d15a841 #v3.28.13
|
||||
uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 #v3.28.16
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
- name: Delete existing comment
|
||||
if: ${{ hashFiles( env.CI_COMMENT_FILE ) == '' }}
|
||||
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 #v2.9.1
|
||||
uses: marocchino/sticky-pull-request-comment@67d0dec7b07ed060a405f9b2a64b8ab319fdd7db #v2.9.2
|
||||
with:
|
||||
header: ${{ env.COMMENT_HEADER }}
|
||||
hide: true
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
|
||||
- name: Add comment
|
||||
if: ${{ hashFiles( env.CI_COMMENT_FILE ) != '' }}
|
||||
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 #v2.9.1
|
||||
uses: marocchino/sticky-pull-request-comment@67d0dec7b07ed060a405f9b2a64b8ab319fdd7db #v2.9.2
|
||||
with:
|
||||
header: ${{ env.COMMENT_HEADER }}
|
||||
path: ${{ env.CI_COMMENT_FILE }}
|
||||
|
||||
@@ -194,7 +194,7 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@v3.8.1
|
||||
uses: sigstore/cosign-installer@v3.8.2
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
|
||||
|
||||
|
||||
+49
-41
@@ -1,15 +1,8 @@
|
||||
issues:
|
||||
max-same-issues: 25
|
||||
uniq-by-line: false
|
||||
|
||||
# TODO: enable this when we have coverage on docstring comments
|
||||
# # The list of ids of default excludes to include or disable.
|
||||
# include:
|
||||
# - EXC0002 # disable excluding of issues about comments from golint
|
||||
|
||||
version: "2"
|
||||
run:
|
||||
tests: false
|
||||
linters:
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
disable-all: true
|
||||
default: none
|
||||
enable:
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
@@ -22,11 +15,8 @@ linters:
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
@@ -34,37 +24,35 @@ linters:
|
||||
- nolintlint
|
||||
- revive
|
||||
- staticcheck
|
||||
- stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- whitespace
|
||||
|
||||
linters-settings:
|
||||
funlen:
|
||||
# Checks the number of lines in a function.
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 60
|
||||
lines: 70
|
||||
# Checks the number of statements in a function.
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 40
|
||||
statements: 50
|
||||
gocritic:
|
||||
enabled-checks:
|
||||
- deferInLoop
|
||||
- ruleguard
|
||||
settings:
|
||||
ruleguard:
|
||||
rules: "test/rules/rules.go"
|
||||
gosec:
|
||||
excludes:
|
||||
- G115
|
||||
|
||||
run:
|
||||
timeout: 10m
|
||||
tests: false
|
||||
settings:
|
||||
funlen:
|
||||
lines: 70
|
||||
statements: 50
|
||||
gocritic:
|
||||
enabled-checks:
|
||||
- deferInLoop
|
||||
- ruleguard
|
||||
settings:
|
||||
ruleguard:
|
||||
rules: test/rules/rules.go
|
||||
gosec:
|
||||
excludes:
|
||||
- G115
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
# do not enable...
|
||||
# - deadcode # The owner seems to have abandoned the linter. Replaced by "unused".
|
||||
@@ -91,3 +79,23 @@ run:
|
||||
# - testpackage
|
||||
# - varcheck # The owner seems to have abandoned the linter. Replaced by "unused".
|
||||
# - wsl # this doens't have an auto-fixer yet and is pretty noisy (https://github.com/bombsimon/wsl/issues/90)
|
||||
|
||||
issues:
|
||||
max-same-issues: 25
|
||||
uniq-by-line: false
|
||||
|
||||
# TODO: enable this when we have coverage on docstring comments
|
||||
# # The list of ids of default excludes to include or disable.
|
||||
# include:
|
||||
# - EXC0002 # disable excluding of issues about comments from golint
|
||||
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
@@ -227,6 +227,16 @@ rough outline how that works:
|
||||
|
||||
## Testing
|
||||
|
||||
### Testing commands
|
||||
|
||||
* `make help` shows a list of available commands
|
||||
* `make unit`, `make integration`, `make cli`, and `make acceptance` run those test suites (see below)
|
||||
* `make test` runs all those tests (and is therefore pretty slow)
|
||||
* `make fixtures` clears and re-fetches all test fixtures.
|
||||
* `go test ./syft/pkg/` for example can test particular packages, assuming fixtures are already made
|
||||
* `make clean-cache` cleans all test cache. Note that subsequent test runs will be slower after this
|
||||
|
||||
|
||||
### Levels of testing
|
||||
|
||||
- `unit`: The default level of test which is distributed throughout the repo are unit tests. Any `_test.go` file that
|
||||
|
||||
+1
-1
@@ -224,7 +224,7 @@ tasks:
|
||||
- "go run -race cmd/syft/main.go alpine:latest"
|
||||
|
||||
validate-cyclonedx-schema:
|
||||
desc: Run integration tests
|
||||
desc: Validate that Syft produces valid CycloneDX documents
|
||||
cmds:
|
||||
- "cd schema/cyclonedx && make"
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ func Attest(app clio.Application) *cobra.Command {
|
||||
opts := defaultAttestOptions()
|
||||
|
||||
// template format explicitly not allowed
|
||||
opts.Format.Template.Enabled = false
|
||||
opts.Template.Enabled = false
|
||||
|
||||
return app.SetupCommand(&cobra.Command{
|
||||
Use: "attest --output [FORMAT] <IMAGE>",
|
||||
@@ -136,7 +136,7 @@ func writeSBOMToFormattedFile(s *sbom.SBOM, sbomFile io.Writer, opts *attestOpti
|
||||
return fmt.Errorf("no output file provided")
|
||||
}
|
||||
|
||||
encs, err := opts.Format.Encoders()
|
||||
encs, err := opts.Encoders()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create encoders: %w", err)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/anchore/clio"
|
||||
"github.com/anchore/syft/cmd/syft/internal/options"
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/task"
|
||||
"github.com/anchore/syft/syft/cataloging"
|
||||
@@ -86,11 +87,13 @@ func runCatalogerList(opts *catalogerListOptions) error {
|
||||
}
|
||||
|
||||
func catalogerListReport(opts *catalogerListOptions, allTaskGroups [][]task.Task) (string, error) {
|
||||
defaultCatalogers := options.Flatten(opts.DefaultCatalogers)
|
||||
selectCatalogers := options.Flatten(opts.SelectCatalogers)
|
||||
selectedTaskGroups, selectionEvidence, err := task.SelectInGroups(
|
||||
allTaskGroups,
|
||||
cataloging.NewSelectionRequest().
|
||||
WithDefaults(opts.DefaultCatalogers...).
|
||||
WithExpression(opts.SelectCatalogers...),
|
||||
WithDefaults(defaultCatalogers...).
|
||||
WithExpression(selectCatalogers...),
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to select catalogers: %w", err)
|
||||
@@ -99,7 +102,7 @@ func catalogerListReport(opts *catalogerListOptions, allTaskGroups [][]task.Task
|
||||
|
||||
switch opts.Output {
|
||||
case "json":
|
||||
report, err = renderCatalogerListJSON(flattenTaskGroups(selectedTaskGroups), selectionEvidence, opts.DefaultCatalogers, opts.SelectCatalogers)
|
||||
report, err = renderCatalogerListJSON(flattenTaskGroups(selectedTaskGroups), selectionEvidence, defaultCatalogers, selectCatalogers)
|
||||
case "table", "":
|
||||
if opts.ShowHidden {
|
||||
report = renderCatalogerListTables(allTaskGroups, selectionEvidence)
|
||||
|
||||
@@ -184,11 +184,11 @@ Default selections: 1
|
||||
• 'image'
|
||||
Selection expressions: 6
|
||||
• 'b' (intersect)
|
||||
• '-directory' (remove)
|
||||
• '-c' (remove)
|
||||
• '-directory' (remove)
|
||||
• '-file' (remove)
|
||||
• '+task3' (add)
|
||||
• '+file-task1' (add)
|
||||
• '+task3' (add)
|
||||
┌────────────────┬──────────────────┐
|
||||
│ FILE CATALOGER │ TAGS │
|
||||
├────────────────┼──────────────────┤
|
||||
@@ -200,6 +200,43 @@ Selection expressions: 6
|
||||
│ task1 │ 1, a, b, image │
|
||||
│ task3 │ 3, c, d, directory │
|
||||
└───────────────────┴────────────────────┘
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "with comma separated expressions, table",
|
||||
options: func() *catalogerListOptions {
|
||||
c := defaultCatalogerListOptions()
|
||||
c.Output = "table"
|
||||
c.DefaultCatalogers = []string{
|
||||
"image,task3,file-task1",
|
||||
}
|
||||
c.SelectCatalogers = []string{
|
||||
"-task2,c,b",
|
||||
}
|
||||
return c
|
||||
}(),
|
||||
want: `
|
||||
Default selections: 4
|
||||
• 'file-task1'
|
||||
• 'image'
|
||||
• 'task3'
|
||||
• 'file'
|
||||
Selection expressions: 3
|
||||
• 'b' (intersect)
|
||||
• 'c' (intersect)
|
||||
• '-task2' (remove)
|
||||
┌────────────────┬──────────────────┐
|
||||
│ FILE CATALOGER │ TAGS │
|
||||
├────────────────┼──────────────────┤
|
||||
│ file-task1 │ file, ft, ft-1-b │
|
||||
│ file-task2 │ file, ft, ft-2-b │
|
||||
└────────────────┴──────────────────┘
|
||||
┌───────────────────┬────────────────────┐
|
||||
│ PACKAGE CATALOGER │ TAGS │
|
||||
├───────────────────┼────────────────────┤
|
||||
│ task1 │ 1, a, b, image │
|
||||
│ task3 │ 3, c, d, directory │
|
||||
└───────────────────┴────────────────────┘
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -219,7 +256,7 @@ Selection expressions: 6
|
||||
return c
|
||||
}(),
|
||||
want: `
|
||||
{"default":["image"],"selection":["-directory","+task3","-c","b"],"catalogers":[{"name":"file-task1","tags":["file"]},{"name":"file-task2","tags":["file"]},{"name":"task1","tags":["b","image"]},{"name":"task3","tags":["task3"]}]}
|
||||
{"default":["image"],"selection":["+task3","-c","-directory","b"],"catalogers":[{"name":"file-task1","tags":["file"]},{"name":"file-task2","tags":["file"]},{"name":"task1","tags":["b","image"]},{"name":"task3","tags":["task3"]}]}
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ func (o *scanOptions) PostLoad() error {
|
||||
}
|
||||
|
||||
func (o *scanOptions) validateLegacyOptionsNotUsed() error {
|
||||
if len(fangs.Flatten(o.Config.ConfigFile)) == 0 {
|
||||
if len(fangs.Flatten(o.ConfigFile)) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ func (o *scanOptions) validateLegacyOptionsNotUsed() error {
|
||||
File any `yaml:"file" json:"file" mapstructure:"file"`
|
||||
}
|
||||
|
||||
for _, f := range fangs.Flatten(o.Config.ConfigFile) {
|
||||
for _, f := range fangs.Flatten(o.ConfigFile) {
|
||||
by, err := os.ReadFile(f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read config file during validations %q: %w", f, err)
|
||||
|
||||
@@ -170,6 +170,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config {
|
||||
Dotnet: dotnet.DefaultCatalogerConfig().
|
||||
WithDepPackagesMustHaveDLL(cfg.Dotnet.DepPackagesMustHaveDLL).
|
||||
WithDepPackagesMustClaimDLL(cfg.Dotnet.DepPackagesMustClaimDLL).
|
||||
WithPropagateDLLClaimsToParents(cfg.Dotnet.PropagateDLLClaimsToParents).
|
||||
WithRelaxDLLClaimsWhenBundlingDetected(cfg.Dotnet.RelaxDLLClaimsWhenBundlingDetected),
|
||||
Golang: golang.DefaultCatalogerConfig().
|
||||
WithSearchLocalModCacheLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Go, task.Golang), cfg.Golang.SearchLocalModCacheLicenses)).
|
||||
@@ -272,12 +273,12 @@ func (cfg *Catalog) PostLoad() error {
|
||||
return fmt.Errorf("cannot use both 'catalogers' and 'select-catalogers'/'default-catalogers' flags")
|
||||
}
|
||||
|
||||
cfg.From = flatten(cfg.From)
|
||||
cfg.From = Flatten(cfg.From)
|
||||
|
||||
cfg.Catalogers = flatten(cfg.Catalogers)
|
||||
cfg.DefaultCatalogers = flatten(cfg.DefaultCatalogers)
|
||||
cfg.SelectCatalogers = flatten(cfg.SelectCatalogers)
|
||||
cfg.Enrich = flatten(cfg.Enrich)
|
||||
cfg.Catalogers = Flatten(cfg.Catalogers)
|
||||
cfg.DefaultCatalogers = Flatten(cfg.DefaultCatalogers)
|
||||
cfg.SelectCatalogers = Flatten(cfg.SelectCatalogers)
|
||||
cfg.Enrich = Flatten(cfg.Enrich)
|
||||
|
||||
// for backwards compatibility
|
||||
cfg.DefaultCatalogers = append(cfg.DefaultCatalogers, cfg.Catalogers...)
|
||||
@@ -295,7 +296,7 @@ func (cfg *Catalog) PostLoad() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func flatten(commaSeparatedEntries []string) []string {
|
||||
func Flatten(commaSeparatedEntries []string) []string {
|
||||
var out []string
|
||||
for _, v := range commaSeparatedEntries {
|
||||
for _, s := range strings.Split(v, ",") {
|
||||
|
||||
@@ -139,7 +139,7 @@ func Test_enrichmentEnabled(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.directives, func(t *testing.T) {
|
||||
got := enrichmentEnabled(flatten([]string{test.directives}), test.test)
|
||||
got := enrichmentEnabled(Flatten([]string{test.directives}), test.test)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ type dotnetConfig struct {
|
||||
|
||||
DepPackagesMustClaimDLL bool `mapstructure:"dep-packages-must-claim-dll" json:"dep-packages-must-claim-dll" yaml:"dep-packages-must-claim-dll"`
|
||||
|
||||
PropagateDLLClaimsToParents bool `mapstructure:"propagate-dll-claims-to-parents" json:"propagate-dll-claims-to-parents" yaml:"propagate-dll-claims-to-parents"`
|
||||
|
||||
RelaxDLLClaimsWhenBundlingDetected bool `mapstructure:"relax-dll-claims-when-bundling-detected" json:"relax-dll-claims-when-bundling-detected" yaml:"relax-dll-claims-when-bundling-detected"`
|
||||
}
|
||||
|
||||
@@ -18,8 +20,9 @@ var _ interface {
|
||||
} = (*dotnetConfig)(nil)
|
||||
|
||||
func (o *dotnetConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.DepPackagesMustHaveDLL, `only keep dep.json packages which an executable on disk can be found for`)
|
||||
descriptions.Add(&o.DepPackagesMustClaimDLL, `only keep dep.json packages which have a runtime/resource DLL claimed in the deps.json targets section (but not necessarily found on disk)`)
|
||||
descriptions.Add(&o.DepPackagesMustHaveDLL, `only keep dep.json packages which an executable on disk is found. The package is also included if a DLL is found for any child package, even if the package itself does not have a DLL.`)
|
||||
descriptions.Add(&o.DepPackagesMustClaimDLL, `only keep dep.json packages which have a runtime/resource DLL claimed in the deps.json targets section (but not necessarily found on disk). The package is also included if any child package claims a DLL, even if the package itself does not claim a DLL.`)
|
||||
descriptions.Add(&o.PropagateDLLClaimsToParents, `treat DLL claims or on-disk evidence for child packages as DLL claims or on-disk evidence for any parent package`)
|
||||
descriptions.Add(&o.RelaxDLLClaimsWhenBundlingDetected, `show all packages from the deps.json if bundling tooling is present as a dependency (e.g. ILRepack)`)
|
||||
}
|
||||
|
||||
@@ -28,6 +31,7 @@ func defaultDotnetConfig() dotnetConfig {
|
||||
return dotnetConfig{
|
||||
DepPackagesMustHaveDLL: def.DepPackagesMustHaveDLL,
|
||||
DepPackagesMustClaimDLL: def.DepPackagesMustClaimDLL,
|
||||
PropagateDLLClaimsToParents: def.PropagateDLLClaimsToParents,
|
||||
RelaxDLLClaimsWhenBundlingDetected: def.RelaxDLLClaimsWhenBundlingDetected,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func (o Output) SBOMWriter() (sbom.Writer, error) {
|
||||
|
||||
usesTemplateOutput := names.Has(string(template.ID))
|
||||
|
||||
if usesTemplateOutput && o.Format.Template.Path == "" {
|
||||
if usesTemplateOutput && o.Template.Path == "" {
|
||||
return nil, fmt.Errorf(`must specify path to template file when using "template" output format`)
|
||||
}
|
||||
|
||||
|
||||
@@ -36,11 +36,7 @@ func capture(target **os.File, writer io.Writer, bufSize int) func() {
|
||||
}()
|
||||
|
||||
buf := make([]byte, bufSize)
|
||||
for {
|
||||
if original == nil {
|
||||
break
|
||||
}
|
||||
|
||||
for original != nil {
|
||||
n, err := r.Read(buf)
|
||||
if n > 0 {
|
||||
_, _ = writer.Write(buf[0:n])
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"path"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -76,7 +77,6 @@ func newAlpineConfiguration(resolver file.Resolver) (*AlpineConfiguration, []fil
|
||||
return &AlpineConfiguration{
|
||||
APKKeys: keys,
|
||||
}, locations, nil
|
||||
|
||||
}
|
||||
|
||||
func getVersion(resolver file.Resolver) (string, []file.Location, error) {
|
||||
@@ -92,6 +92,7 @@ func getVersion(resolver file.Resolver) (string, []file.Location, error) {
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("unable to read alpine version: %w", err)
|
||||
}
|
||||
defer internal.CloseAndLogError(reader, locations[0].RealPath)
|
||||
|
||||
version, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
@@ -111,7 +112,11 @@ func getAPKKeys(resolver file.Resolver) (map[string]string, []file.Location, err
|
||||
}
|
||||
for _, location := range locations {
|
||||
basename := path.Base(location.RealPath)
|
||||
//nolint:gocritic
|
||||
reader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to resolve file contents by location at %s: %w", location.RealPath, err)
|
||||
}
|
||||
content, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to read apk key content at %s: %w", location.RealPath, err)
|
||||
|
||||
@@ -124,5 +124,4 @@ func showAlpineConfiguration(s sbom.SBOM) {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(meta))
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ func main() {
|
||||
if err := enc.Encode(sbom.Descriptor.Configuration); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func imageReference() string {
|
||||
|
||||
@@ -22,13 +22,13 @@ 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.20250220190351-d62adb6e1115
|
||||
github.com/anchore/stereoscope v0.1.2
|
||||
github.com/anchore/stereoscope v0.1.4
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
||||
github.com/aquasecurity/go-pep440-version v0.0.1
|
||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1
|
||||
github.com/charmbracelet/bubbles v0.20.0
|
||||
github.com/charmbracelet/bubbles v0.21.0
|
||||
github.com/charmbracelet/bubbletea v1.3.4
|
||||
github.com/charmbracelet/lipgloss v1.1.0
|
||||
github.com/dave/jennifer v1.7.1
|
||||
@@ -40,7 +40,7 @@ require (
|
||||
github.com/github/go-spdx/v2 v2.3.2
|
||||
github.com/gkampitakis/go-snaps v0.5.11
|
||||
github.com/go-git/go-billy/v5 v5.6.2
|
||||
github.com/go-git/go-git/v5 v5.14.0
|
||||
github.com/go-git/go-git/v5 v5.16.0
|
||||
github.com/go-test/deep v1.1.1
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1
|
||||
github.com/gohugoio/hashstructure v0.5.0
|
||||
@@ -57,8 +57,8 @@ require (
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
|
||||
github.com/knqyf263/go-rpmdb v0.1.1
|
||||
github.com/magiconair/properties v1.8.9
|
||||
github.com/mholt/archives v0.1.0
|
||||
github.com/magiconair/properties v1.8.10
|
||||
github.com/mholt/archives v0.1.1
|
||||
github.com/moby/sys/mountinfo v0.7.2
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
@@ -85,7 +85,7 @@ require (
|
||||
go.uber.org/goleak v1.3.0
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
|
||||
golang.org/x/mod v0.24.0
|
||||
golang.org/x/net v0.38.0
|
||||
golang.org/x/net v0.39.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.37.0
|
||||
)
|
||||
@@ -118,7 +118,7 @@ require (
|
||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/cloudflare/circl v1.6.0 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/containerd/containerd v1.7.27 // indirect
|
||||
github.com/containerd/containerd/api v1.8.0 // indirect
|
||||
@@ -132,9 +132,9 @@ require (
|
||||
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/docker/cli v28.0.4+incompatible // indirect
|
||||
github.com/docker/cli v28.1.1+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v28.0.4+incompatible // indirect
|
||||
github.com/docker/docker v28.1.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||
@@ -145,7 +145,7 @@ require (
|
||||
github.com/felixge/fgprof v0.9.5 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/gkampitakis/ciinfo v0.3.1 // indirect
|
||||
github.com/gkampitakis/go-diff v1.3.2 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
@@ -182,7 +182,7 @@ require (
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0 // indirect
|
||||
github.com/moby/sys/user v0.3.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
@@ -191,7 +191,7 @@ require (
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.1.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||
@@ -240,11 +240,11 @@ require (
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/term v0.30.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/term v0.31.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/tools v0.31.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
|
||||
@@ -259,6 +259,8 @@ require (
|
||||
|
||||
require github.com/anchore/go-sync v0.0.0-20250326131806-4eda43a485b6
|
||||
|
||||
require github.com/minio/minlz v1.0.0 // indirect
|
||||
|
||||
retract (
|
||||
v0.53.2
|
||||
v0.53.1 // Published accidentally with incorrect license in depdencies
|
||||
|
||||
@@ -122,8 +122,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.20250220190351-d62adb6e1115 h1:ZyRCmiEjnoGJZ1+Ah0ZZ/mKKqNhGcUZBl0s7PTTDzvY=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI=
|
||||
github.com/anchore/stereoscope v0.1.2 h1:0+Jcf7hoImYKfrH2XzN6vvbmbpm68A/woabC43gZ4eU=
|
||||
github.com/anchore/stereoscope v0.1.2/go.mod h1:kU4LkiocOimxuSnlmJgilHCfDMCR5t/UroKIpzI8jNw=
|
||||
github.com/anchore/stereoscope v0.1.4 h1:e+iT9UdUzLBabWGe84hn5sTHDRioY+4IHsVzJXuJlek=
|
||||
github.com/anchore/stereoscope v0.1.4/go.mod h1:omWgXDEp/XfqCJlZXIByEo1c3ArZg/qTJ5LBKVLAIdw=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
@@ -149,6 +149,8 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||
github.com/becheran/wildmatch-go v1.0.0 h1:mE3dGGkTmpKtT4Z+88t8RStG40yN9T+kFEGj2PZFSzA=
|
||||
github.com/becheran/wildmatch-go v1.0.0/go.mod h1:gbMvj0NtVdJ15Mg/mH9uxk2R1QCistMyU7d9KFzroX4=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
@@ -179,8 +181,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
|
||||
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
|
||||
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||
github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
|
||||
github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
||||
@@ -193,6 +195,8 @@ github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2ll
|
||||
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
@@ -207,8 +211,8 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@@ -260,12 +264,12 @@ github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4i
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v28.0.4+incompatible h1:pBJSJeNd9QeIWPjRcV91RVJihd/TXB77q1ef64XEu4A=
|
||||
github.com/docker/cli v28.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k=
|
||||
github.com/docker/cli v28.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v28.0.4+incompatible h1:JNNkBctYKurkw6FrHfKqY0nKIDf5nrbxjVBtS+cdcok=
|
||||
github.com/docker/docker v28.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I=
|
||||
github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
@@ -316,8 +320,8 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/github/go-spdx/v2 v2.3.2 h1:IfdyNHTqzs4zAJjXdVQfRnxt1XMfycXoHBE2Vsm1bjs=
|
||||
github.com/github/go-spdx/v2 v2.3.2/go.mod h1:2ZxKsOhvBp+OYBDlsGnUMcchLeo2mrpEBn2L1C+U3IQ=
|
||||
@@ -337,8 +341,8 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60=
|
||||
github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k=
|
||||
github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ=
|
||||
github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -569,8 +573,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
||||
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
|
||||
github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
|
||||
@@ -598,11 +602,13 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mholt/archives v0.1.0 h1:FacgJyrjiuyomTuNA92X5GyRBRZjE43Y/lrzKIlF35Q=
|
||||
github.com/mholt/archives v0.1.0/go.mod h1:j/Ire/jm42GN7h90F5kzj6hf6ZFzEH66de+hmjEKu+I=
|
||||
github.com/mholt/archives v0.1.1 h1:c7J3qXN1FB54y0qiUXiq9Bxk4eCUc8pdXWwOhZdRzeY=
|
||||
github.com/mholt/archives v0.1.1/go.mod h1:FQVz01Q2uXKB/35CXeW/QFO23xT+hSCGZHVtha78U4I=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/minio/minlz v1.0.0 h1:Kj7aJZ1//LlTP1DM8Jm7lNKvvJS2m74gyyXXn3+uJWQ=
|
||||
github.com/minio/minlz v1.0.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
|
||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
@@ -620,10 +626,12 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
||||
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||
github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
|
||||
github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
|
||||
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
||||
@@ -650,8 +658,8 @@ github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdh
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
||||
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78 h1:MYzLheyVx1tJVDqfu3YnN4jtnyALNzLvwl+f58TcvQY=
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
||||
github.com/nwaples/rardecode/v2 v2.1.0 h1:JQl9ZoBPDy+nIZGb1mx8+anfHp/LV3NE2MjMiv0ct/U=
|
||||
github.com/nwaples/rardecode/v2 v2.1.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
@@ -915,8 +923,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
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=
|
||||
@@ -1002,8 +1010,8 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
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=
|
||||
@@ -1033,8 +1041,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1110,13 +1118,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/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.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
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=
|
||||
@@ -1127,8 +1135,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
@@ -13,5 +13,5 @@ func DefaultLocationComparer(x, y file.Location) bool {
|
||||
}
|
||||
|
||||
func LocationComparerWithoutLayer(x, y file.Location) bool {
|
||||
return cmp.Equal(x.Coordinates.RealPath, y.Coordinates.RealPath) && cmp.Equal(x.AccessPath, y.AccessPath)
|
||||
return cmp.Equal(x.RealPath, y.RealPath) && cmp.Equal(x.AccessPath, y.AccessPath)
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ package internal
|
||||
const (
|
||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||
JSONSchemaVersion = "16.0.24"
|
||||
JSONSchemaVersion = "16.0.25"
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@ func ExtractGlobsFromTarToUniqueTempFile(archivePath, dir string, globs ...strin
|
||||
defer file.Close()
|
||||
|
||||
// ignore directories
|
||||
if file.FileInfo.IsDir() {
|
||||
if file.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ func NewZipFileManifest(archivePath string) (ZipFileManifest, error) {
|
||||
}
|
||||
}()
|
||||
|
||||
for _, file := range zipReader.Reader.File {
|
||||
for _, file := range zipReader.File {
|
||||
manifest.Add(file.Name, file.FileInfo())
|
||||
}
|
||||
return manifest, nil
|
||||
|
||||
@@ -53,7 +53,7 @@ func TraverseFilesInZip(archivePath string, visitor func(*zip.File) error, paths
|
||||
}
|
||||
}()
|
||||
|
||||
for _, file := range zipReader.Reader.File {
|
||||
for _, file := range zipReader.File {
|
||||
// if no paths are given then assume that all files should be traversed
|
||||
if len(paths) > 0 {
|
||||
if _, ok := request[file.Name]; !ok {
|
||||
|
||||
@@ -6,12 +6,19 @@ import (
|
||||
|
||||
type licenseScannerKey struct{}
|
||||
|
||||
var ctxKey = licenseScannerKey{}
|
||||
|
||||
func SetContextLicenseScanner(ctx context.Context, s Scanner) context.Context {
|
||||
return context.WithValue(ctx, licenseScannerKey{}, s)
|
||||
return context.WithValue(ctx, ctxKey, s)
|
||||
}
|
||||
|
||||
func IsContextLicenseScannerSet(ctx context.Context) bool {
|
||||
_, ok := ctx.Value(ctxKey).(Scanner)
|
||||
return ok
|
||||
}
|
||||
|
||||
func ContextLicenseScanner(ctx context.Context) (Scanner, error) {
|
||||
if s, ok := ctx.Value(licenseScannerKey{}).(Scanner); ok {
|
||||
if s, ok := ctx.Value(ctxKey).(Scanner); ok {
|
||||
return s, nil
|
||||
}
|
||||
return NewDefaultScanner()
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package licenses
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSetContextLicenseScanner(t *testing.T) {
|
||||
scanner := testScanner(true)
|
||||
ctx := context.Background()
|
||||
ctx = SetContextLicenseScanner(ctx, scanner)
|
||||
|
||||
val := ctx.Value(ctxKey)
|
||||
require.NotNil(t, val)
|
||||
s, ok := val.(Scanner)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, scanner, s)
|
||||
}
|
||||
|
||||
func TestIsContextLicenseScannerSet(t *testing.T) {
|
||||
scanner := testScanner(true)
|
||||
ctx := context.Background()
|
||||
require.False(t, IsContextLicenseScannerSet(ctx))
|
||||
|
||||
ctx = SetContextLicenseScanner(ctx, scanner)
|
||||
require.True(t, IsContextLicenseScannerSet(ctx))
|
||||
}
|
||||
|
||||
func TestContextLicenseScanner(t *testing.T) {
|
||||
t.Run("with scanner", func(t *testing.T) {
|
||||
scanner := testScanner(true)
|
||||
ctx := SetContextLicenseScanner(context.Background(), scanner)
|
||||
s, err := ContextLicenseScanner(ctx)
|
||||
if err != nil || s != scanner {
|
||||
t.Fatal("expected scanner from context")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("without scanner", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s, err := ContextLicenseScanner(ctx)
|
||||
if err != nil || s == nil {
|
||||
t.Fatal("expected default scanner")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/sbomsync"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
@@ -32,11 +33,11 @@ type ownershipByFilesMetadata struct {
|
||||
Files []string `json:"files"`
|
||||
}
|
||||
|
||||
func ByFileOwnershipOverlapWorker(accessor sbomsync.Accessor) {
|
||||
func ByFileOwnershipOverlapWorker(resolver file.Resolver, accessor sbomsync.Accessor) {
|
||||
var relationships []artifact.Relationship
|
||||
|
||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||
relationships = byFileOwnershipOverlap(s.Artifacts.Packages)
|
||||
relationships = byFileOwnershipOverlap(resolver, s.Artifacts.Packages)
|
||||
})
|
||||
|
||||
accessor.WriteToSBOM(func(s *sbom.SBOM) {
|
||||
@@ -46,8 +47,8 @@ func ByFileOwnershipOverlapWorker(accessor sbomsync.Accessor) {
|
||||
|
||||
// byFileOwnershipOverlap creates a package-to-package relationship based on discovering which packages have
|
||||
// evidence locations that overlap with ownership claim from another package's package manager metadata.
|
||||
func byFileOwnershipOverlap(catalog *pkg.Collection) []artifact.Relationship {
|
||||
var relationships = findOwnershipByFilesRelationships(catalog)
|
||||
func byFileOwnershipOverlap(resolver file.Resolver, catalog *pkg.Collection) []artifact.Relationship {
|
||||
var relationships = findOwnershipByFilesRelationships(resolver, catalog)
|
||||
|
||||
var edges []artifact.Relationship
|
||||
for parentID, children := range relationships {
|
||||
@@ -84,7 +85,7 @@ func byFileOwnershipOverlap(catalog *pkg.Collection) []artifact.Relationship {
|
||||
|
||||
// findOwnershipByFilesRelationships find overlaps in file ownership with a file that defines another package. Specifically, a .Location.Path of
|
||||
// a package is found to be owned by another (from the owner's .Metadata.Files[]).
|
||||
func findOwnershipByFilesRelationships(catalog *pkg.Collection) map[artifact.ID]map[artifact.ID]*strset.Set {
|
||||
func findOwnershipByFilesRelationships(resolver file.Resolver, catalog *pkg.Collection) map[artifact.ID]map[artifact.ID]*strset.Set { //nolint:gocognit
|
||||
var relationships = make(map[artifact.ID]map[artifact.ID]*strset.Set)
|
||||
|
||||
if catalog == nil {
|
||||
@@ -102,27 +103,31 @@ func findOwnershipByFilesRelationships(catalog *pkg.Collection) map[artifact.ID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, ownedFilePath := range pkgFileOwner.OwnedFiles() {
|
||||
if matchesAny(ownedFilePath, globsForbiddenFromBeingOwned) {
|
||||
// we skip over known exceptions to file ownership, such as the RPM package owning
|
||||
// the RPM DB path, otherwise the RPM package would "own" all RPMs, which is not intended
|
||||
continue
|
||||
}
|
||||
|
||||
// look for package(s) in the catalog that may be owned by this package and mark the relationship
|
||||
for _, subPackage := range catalog.PackagesByPath(ownedFilePath) {
|
||||
subID := subPackage.ID()
|
||||
if subID == id {
|
||||
for _, ownedFilePath := range pkgFileOwner.OwnedFiles() {
|
||||
// find the first path that results in a hit
|
||||
for _, ownedPath := range allPaths(ownedFilePath, resolver) {
|
||||
if matchesAny(ownedPath, globsForbiddenFromBeingOwned) {
|
||||
// we skip over known exceptions to file ownership, such as the RPM package owning
|
||||
// the RPM DB path, otherwise the RPM package would "own" all RPMs, which is not intended
|
||||
continue
|
||||
}
|
||||
if _, exists := relationships[id]; !exists {
|
||||
relationships[id] = make(map[artifact.ID]*strset.Set)
|
||||
}
|
||||
|
||||
if _, exists := relationships[id][subID]; !exists {
|
||||
relationships[id][subID] = strset.New()
|
||||
// look for package(s) in the catalog that may be owned by this package and mark the relationship
|
||||
for _, subPackage := range catalog.PackagesByPath(ownedPath) {
|
||||
subID := subPackage.ID()
|
||||
if subID == id {
|
||||
continue
|
||||
}
|
||||
if _, exists := relationships[id]; !exists {
|
||||
relationships[id] = make(map[artifact.ID]*strset.Set)
|
||||
}
|
||||
|
||||
if _, exists := relationships[id][subID]; !exists {
|
||||
relationships[id][subID] = strset.New()
|
||||
}
|
||||
relationships[id][subID].Add(ownedPath)
|
||||
}
|
||||
relationships[id][subID].Add(ownedFilePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +135,25 @@ func findOwnershipByFilesRelationships(catalog *pkg.Collection) map[artifact.ID]
|
||||
return relationships
|
||||
}
|
||||
|
||||
func allPaths(ownedFilePath string, resolver file.Resolver) []string {
|
||||
// though we have a string path, we need to resolve symlinks and other filesystem oddities since we cannot assume this is a real path
|
||||
var locs []file.Location
|
||||
var err error
|
||||
if resolver != nil {
|
||||
locs, err = resolver.FilesByPath(ownedFilePath)
|
||||
if err != nil {
|
||||
log.WithFields("error", err, "path", ownedFilePath).Trace("unable to find path for owned file")
|
||||
locs = nil
|
||||
}
|
||||
}
|
||||
|
||||
ownedFilePaths := strset.New(ownedFilePath)
|
||||
for _, loc := range locs {
|
||||
ownedFilePaths.Add(loc.RealPath)
|
||||
}
|
||||
return ownedFilePaths.List()
|
||||
}
|
||||
|
||||
func matchesAny(s string, globs []string) bool {
|
||||
for _, g := range globs {
|
||||
matches, err := doublestar.Match(g, s)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/internal/cmptest"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
@@ -12,11 +12,29 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
type mockFR struct {
|
||||
file.Resolver
|
||||
translate map[string]string
|
||||
}
|
||||
|
||||
func (m mockFR) FilesByPath(paths ...string) ([]file.Location, error) {
|
||||
var results []file.Location
|
||||
for _, p := range paths {
|
||||
tPath, ok := m.translate[p]
|
||||
if !ok {
|
||||
tPath = p
|
||||
}
|
||||
results = append(results, file.NewLocation(tPath))
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func TestOwnershipByFilesRelationship(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t testing.TB) ([]pkg.Package, []artifact.Relationship)
|
||||
name string
|
||||
resolver file.Resolver
|
||||
setup func(t testing.TB) ([]pkg.Package, []artifact.Relationship)
|
||||
}{
|
||||
{
|
||||
name: "owns-by-real-path",
|
||||
@@ -60,6 +78,75 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
|
||||
return []pkg.Package{parent, child}, []artifact.Relationship{relationship}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "misses-by-dead-symlink",
|
||||
resolver: mockFR{
|
||||
translate: map[string]string{
|
||||
"/bin/gzip": "", // treat this as a dead symlink
|
||||
},
|
||||
},
|
||||
setup: func(t testing.TB) ([]pkg.Package, []artifact.Relationship) {
|
||||
parent := pkg.Package{
|
||||
Type: pkg.DebPkg,
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Files: []pkg.DpkgFileRecord{
|
||||
{Path: "/bin/gzip"}, // this symlinks to gzip via /bin -> /usr/bin
|
||||
},
|
||||
},
|
||||
}
|
||||
parent.SetID()
|
||||
|
||||
child := pkg.Package{
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewVirtualLocation("/usr/bin/gzip", "/usr/bin/gzip"),
|
||||
),
|
||||
Type: pkg.BinaryPkg,
|
||||
}
|
||||
child.SetID()
|
||||
|
||||
return []pkg.Package{parent, child}, nil // importantly, no relationship is expected
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "owns-by-symlink",
|
||||
resolver: mockFR{
|
||||
translate: map[string]string{
|
||||
"/bin/gzip": "/usr/bin/gzip", // if there is a string path of /bin/gzip then return the real path of /usr/bin/gzip
|
||||
},
|
||||
},
|
||||
setup: func(t testing.TB) ([]pkg.Package, []artifact.Relationship) {
|
||||
parent := pkg.Package{
|
||||
Type: pkg.DebPkg,
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Files: []pkg.DpkgFileRecord{
|
||||
{Path: "/bin/gzip"}, // this symlinks to gzip via /bin -> /usr/bin
|
||||
},
|
||||
},
|
||||
}
|
||||
parent.SetID()
|
||||
|
||||
child := pkg.Package{
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewVirtualLocation("/usr/bin/gzip", "/usr/bin/gzip"),
|
||||
),
|
||||
Type: pkg.BinaryPkg,
|
||||
}
|
||||
child.SetID()
|
||||
|
||||
relationship := artifact.Relationship{
|
||||
From: parent,
|
||||
To: child,
|
||||
Type: artifact.OwnershipByFileOverlapRelationship,
|
||||
Data: ownershipByFilesMetadata{
|
||||
Files: []string{
|
||||
"/usr/bin/gzip",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return []pkg.Package{parent, child}, []artifact.Relationship{relationship}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "owns-by-virtual-path",
|
||||
setup: func(t testing.TB) ([]pkg.Package, []artifact.Relationship) {
|
||||
@@ -140,9 +227,9 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
pkgs, expectedRelations := test.setup(t)
|
||||
c := pkg.NewCollection(pkgs...)
|
||||
relationships := byFileOwnershipOverlap(c)
|
||||
relationships := byFileOwnershipOverlap(test.resolver, c)
|
||||
|
||||
assert.Len(t, relationships, len(expectedRelations))
|
||||
require.Len(t, relationships, len(expectedRelations))
|
||||
for idx, expectedRelationship := range expectedRelations {
|
||||
actualRelationship := relationships[idx]
|
||||
if d := cmp.Diff(expectedRelationship, actualRelationship, cmptest.DefaultOptions()...); d != "" {
|
||||
|
||||
@@ -22,7 +22,7 @@ func less(i, j artifact.Relationship) bool {
|
||||
jFrom, ok3 := j.From.(pkg.Package)
|
||||
jTo, ok4 := j.To.(pkg.Package)
|
||||
|
||||
if !(ok1 && ok2 && ok3 && ok4) {
|
||||
if !ok1 && !ok2 && !ok3 && !ok4 {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -245,10 +245,10 @@ func packageFileOwnershipRelationships(p pkg.Package, resolver file.PathResolver
|
||||
}
|
||||
|
||||
for _, ref := range pathRefs {
|
||||
if oldRef, ok := locations[ref.Coordinates.ID()]; ok {
|
||||
if oldRef, ok := locations[ref.ID()]; ok {
|
||||
log.Debugf("found path duplicate of %s", oldRef.RealPath)
|
||||
}
|
||||
locations[ref.Coordinates.ID()] = ref
|
||||
locations[ref.ID()] = ref
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ func DefaultPackageTaskFactories() Factories {
|
||||
newSimplePackageTaskFactory(cpp.NewConanInfoCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "cpp", "conan"),
|
||||
newSimplePackageTaskFactory(javascript.NewPackageCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, JavaScript, Node),
|
||||
newSimplePackageTaskFactory(php.NewComposerInstalledCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "php", "composer"),
|
||||
newSimplePackageTaskFactory(r.NewPackageCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "r"),
|
||||
newSimplePackageTaskFactory(r.NewPackageCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, pkgcataloging.DirectoryTag, "r"),
|
||||
newSimplePackageTaskFactory(ruby.NewInstalledGemSpecCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "ruby", "gem", "gemspec"),
|
||||
newSimplePackageTaskFactory(rust.NewAuditBinaryCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "rust", "binary"),
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ func finalizeRelationships(resolver file.Resolver, builder sbomsync.Builder, cfg
|
||||
|
||||
// add relationships showing packages that are evident by a file which is owned by another package (package-to-package)
|
||||
if cfg.PackageFileOwnershipOverlap {
|
||||
relationship.ByFileOwnershipOverlapWorker(accessor)
|
||||
relationship.ByFileOwnershipOverlapWorker(resolver, accessor)
|
||||
}
|
||||
|
||||
// conditionally remove binary packages based on file ownership overlap relationships found
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "anchore.io/schema/syft/json/16.0.24/document",
|
||||
"$id": "anchore.io/schema/syft/json/16.0.25/document",
|
||||
"$ref": "#/$defs/Document",
|
||||
"$defs": {
|
||||
"AlpmDbEntry": {
|
||||
@@ -995,6 +995,20 @@
|
||||
"size"
|
||||
]
|
||||
},
|
||||
"GithubActionsUseStatement": {
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"comment": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"value"
|
||||
]
|
||||
},
|
||||
"GoModuleBuildinfoEntry": {
|
||||
"properties": {
|
||||
"goBuildSettings": {
|
||||
@@ -1804,6 +1818,9 @@
|
||||
{
|
||||
"$ref": "#/$defs/ErlangRebarLockEntry"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/GithubActionsUseStatement"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/GoModuleBuildinfoEntry"
|
||||
},
|
||||
|
||||
+11
-4
@@ -96,14 +96,21 @@ func setupContext(ctx context.Context, cfg *CreateSBOMConfig) (context.Context,
|
||||
ctx = setContextExecutors(ctx, cfg)
|
||||
|
||||
// configure license scanner
|
||||
return setContextLicenseScanner(ctx, cfg)
|
||||
// skip injecting a license scanner if one already set on context
|
||||
if licenses.IsContextLicenseScannerSet(ctx) {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
return SetContextLicenseScanner(ctx, cfg.Licenses)
|
||||
}
|
||||
|
||||
func setContextLicenseScanner(ctx context.Context, cfg *CreateSBOMConfig) (context.Context, error) {
|
||||
// SetContextLicenseScanner creates and sets a license scanner
|
||||
// on the provided context using the provided license config.
|
||||
func SetContextLicenseScanner(ctx context.Context, cfg cataloging.LicenseConfig) (context.Context, error) {
|
||||
// inject a single license scanner and content config for all package cataloging tasks into context
|
||||
licenseScanner, err := licenses.NewDefaultScanner(
|
||||
licenses.WithIncludeLicenseContent(cfg.Licenses.IncludeUnkownLicenseContent),
|
||||
licenses.WithCoverage(cfg.Licenses.Coverage),
|
||||
licenses.WithIncludeLicenseContent(cfg.IncludeUnkownLicenseContent),
|
||||
licenses.WithCoverage(cfg.Coverage),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not build licenseScanner for cataloging: %w", err)
|
||||
|
||||
@@ -48,15 +48,15 @@ func (m *LocationMetadata) merge(other LocationMetadata) error {
|
||||
}
|
||||
|
||||
func (l Location) WithAnnotation(key, value string) Location {
|
||||
if l.LocationMetadata.Annotations == nil {
|
||||
l.LocationMetadata.Annotations = map[string]string{}
|
||||
if l.Annotations == nil {
|
||||
l.Annotations = map[string]string{}
|
||||
}
|
||||
l.LocationMetadata.Annotations[key] = value
|
||||
l.Annotations[key] = value
|
||||
return l
|
||||
}
|
||||
|
||||
func (l Location) WithoutAnnotations() Location {
|
||||
l.LocationMetadata.Annotations = map[string]string{}
|
||||
l.Annotations = map[string]string{}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
@@ -361,6 +361,7 @@ func collectDocRelationships(spdxIDMap map[string]any, doc *spdx.Document) (out
|
||||
from, fromOk := a.(pkg.Package)
|
||||
toPackage, toPackageOk := b.(pkg.Package)
|
||||
toLocation, toLocationOk := b.(file.Location)
|
||||
//nolint:staticcheck
|
||||
if !fromOk || !(toPackageOk || toLocationOk) {
|
||||
log.Debugf("unable to find valid relationship mapping from SPDX, ignoring: (from: %+v) (to: %+v)", a, b)
|
||||
continue
|
||||
|
||||
@@ -213,13 +213,15 @@ func reduceOuter(expression string) string {
|
||||
func isBalanced(expression string) bool {
|
||||
count := 0
|
||||
for _, c := range expression {
|
||||
if c == '(' {
|
||||
switch c {
|
||||
case '(':
|
||||
count++
|
||||
} else if c == ')' {
|
||||
case ')':
|
||||
count--
|
||||
if count < 0 {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
return count == 0
|
||||
|
||||
@@ -34,7 +34,7 @@ const (
|
||||
//
|
||||
// Available options are: <omit>, NOASSERTION, Person: <person>, Organization: <org>
|
||||
// return values are: <type>, <value>
|
||||
func Originator(p pkg.Package) (typ string, author string) { //nolint: funlen
|
||||
func Originator(p pkg.Package) (typ string, author string) { //nolint: gocyclo,funlen
|
||||
if !hasMetadata(p) {
|
||||
return typ, author
|
||||
}
|
||||
@@ -57,6 +57,15 @@ func Originator(p pkg.Package) (typ string, author string) { //nolint: funlen
|
||||
case pkg.DpkgArchiveEntry:
|
||||
author = metadata.Maintainer
|
||||
|
||||
case pkg.GitHubActionsUseStatement:
|
||||
typ = orgType
|
||||
org := strings.Split(metadata.Value, "/")[0]
|
||||
if org == "actions" {
|
||||
// this is a GitHub action, so the org is GitHub
|
||||
org = "GitHub"
|
||||
}
|
||||
author = org
|
||||
|
||||
case pkg.JavaArchive:
|
||||
if metadata.Manifest != nil {
|
||||
author = metadata.Manifest.Main.MustGet("Specification-Vendor")
|
||||
|
||||
@@ -45,6 +45,7 @@ func Test_OriginatorSupplier(t *testing.T) {
|
||||
pkg.SwiplPackEntry{},
|
||||
pkg.OpamPackage{},
|
||||
pkg.YarnLockEntry{},
|
||||
pkg.TerraformLockProviderEntry{},
|
||||
)
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -384,20 +385,24 @@ func Test_OriginatorSupplier(t *testing.T) {
|
||||
supplier: "Person: me (me@auth.com)",
|
||||
},
|
||||
{
|
||||
name: "from ocaml opam",
|
||||
name: "from github actions workflow/action",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.OpamPackage{},
|
||||
Metadata: pkg.GitHubActionsUseStatement{
|
||||
Value: "actions/checkout@v4",
|
||||
},
|
||||
},
|
||||
originator: "",
|
||||
supplier: "",
|
||||
originator: "Organization: GitHub",
|
||||
supplier: "Organization: GitHub",
|
||||
},
|
||||
{
|
||||
name: "from terraform lock",
|
||||
name: "from github actions workflow/action",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.TerraformLockProviderEntry{},
|
||||
Metadata: pkg.GitHubActionsUseStatement{
|
||||
Value: "google/something@v6",
|
||||
},
|
||||
},
|
||||
originator: "",
|
||||
supplier: "",
|
||||
originator: "Organization: google",
|
||||
supplier: "Organization: google",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -58,7 +58,8 @@ func (s *Source) UnmarshalJSON(b []byte) error {
|
||||
func unpackSrcMetadata(s *Source, unpacker sourceUnpacker) error {
|
||||
rt := sourcemetadata.ReflectTypeFromJSONName(s.Type)
|
||||
if rt == nil {
|
||||
return fmt.Errorf("unable to find source metadata type=%q", s.Type)
|
||||
// in cases where we are converting from an SBOM without any source information, we don't want this to be fatal
|
||||
return nil
|
||||
}
|
||||
|
||||
val := reflect.New(rt).Interface()
|
||||
|
||||
@@ -22,6 +22,15 @@ func TestSource_UnmarshalJSON(t *testing.T) {
|
||||
expected *Source
|
||||
wantErr require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
input: []byte(`{
|
||||
"id": "",
|
||||
"type": "",
|
||||
"metadata": null
|
||||
}`),
|
||||
expected: &Source{},
|
||||
},
|
||||
{
|
||||
name: "directory",
|
||||
input: []byte(`{
|
||||
|
||||
@@ -228,7 +228,7 @@ func toSyftRelationships(doc *model.Document, catalog *pkg.Collection, relations
|
||||
idMap[string(p.ID())] = p
|
||||
locations := p.Locations.ToSlice()
|
||||
for _, l := range locations {
|
||||
idMap[string(l.Coordinates.ID())] = l.Coordinates
|
||||
idMap[string(l.ID())] = l.Coordinates
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,11 @@ func (r ChrootContext) ToNativeGlob(chrootPath string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
parts[0] = strings.TrimRight(responsePath, "/") + "/"
|
||||
hasSlash := strings.HasSuffix(parts[0], "/")
|
||||
parts[0] = responsePath
|
||||
if hasSlash {
|
||||
parts[0] = strings.TrimRight(parts[0], "/") + "/"
|
||||
}
|
||||
|
||||
return strings.Join(parts, "*"), nil
|
||||
}
|
||||
|
||||
@@ -558,6 +558,16 @@ func TestToNativeGlob(t *testing.T) {
|
||||
expectedResult: "/cwd/relative/path/**/file*.txt",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "ending with glob",
|
||||
chrootContext: ChrootContext{
|
||||
root: "/root",
|
||||
cwdRelativeToRoot: "/cwd",
|
||||
},
|
||||
chrootPath: "/var/lib/dpkg/info/name.*",
|
||||
expectedResult: "/root/var/lib/dpkg/info/name.*",
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -57,7 +57,7 @@ func (r *ContainerImageAllLayers) fileByRef(ref stereoscopeFile.Reference, uniqu
|
||||
return nil, fmt.Errorf("unable to fetch metadata (ref=%+v): %w", ref, err)
|
||||
}
|
||||
|
||||
if entry.Metadata.Type == stereoscopeFile.TypeHardLink || entry.Metadata.Type == stereoscopeFile.TypeSymLink {
|
||||
if entry.Type == stereoscopeFile.TypeHardLink || entry.Type == stereoscopeFile.TypeSymLink {
|
||||
// a link may resolve in this layer or higher, assuming a squashed tree is used to search
|
||||
// we should search all possible resolutions within the valid source
|
||||
for _, subLayerIdx := range r.layers[layerIdx:] {
|
||||
@@ -102,7 +102,7 @@ func (r *ContainerImageAllLayers) FilesByPath(paths ...string) ([]file.Location,
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get file metadata for path=%q: %w", ref.RealPath, err)
|
||||
}
|
||||
if metadata.Metadata.IsDir() {
|
||||
if metadata.IsDir() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ func (r *ContainerImageAllLayers) FilesByGlob(patterns ...string) ([]file.Locati
|
||||
return nil, fmt.Errorf("unable to get file metadata for path=%q: %w", result.RequestPath, err)
|
||||
}
|
||||
// don't consider directories
|
||||
if metadata.Metadata.IsDir() {
|
||||
if metadata.IsDir() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -192,7 +192,7 @@ func (r *ContainerImageAllLayers) FileContentsByLocation(location file.Location)
|
||||
return nil, fmt.Errorf("unable to get metadata for path=%q from file catalog: %w", location.RealPath, err)
|
||||
}
|
||||
|
||||
switch entry.Metadata.Type {
|
||||
switch entry.Type {
|
||||
case stereoscopeFile.TypeSymLink, stereoscopeFile.TypeHardLink:
|
||||
// the location we are searching may be a symlink, we should always work with the resolved file
|
||||
newLocation := r.RelativeFileByPath(location, location.AccessPath)
|
||||
|
||||
@@ -58,7 +58,7 @@ func (r *ContainerImageSquash) FilesByPath(paths ...string) ([]file.Location, er
|
||||
return nil, fmt.Errorf("unable to get file metadata for path=%q: %w", ref.RealPath, err)
|
||||
}
|
||||
// don't consider directories
|
||||
if metadata.Metadata.IsDir() {
|
||||
if metadata.IsDir() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ func (r *ContainerImageSquash) FilesByGlob(patterns ...string) ([]file.Location,
|
||||
return nil, fmt.Errorf("unable to get file metadata for path=%q: %w", result.RequestPath, err)
|
||||
}
|
||||
// don't consider directories
|
||||
if metadata.Metadata.IsDir() {
|
||||
if metadata.IsDir() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -151,7 +151,7 @@ func (r *ContainerImageSquash) FileContentsByLocation(location file.Location) (i
|
||||
return nil, fmt.Errorf("unable to get metadata for path=%q from file catalog: %w", location.RealPath, err)
|
||||
}
|
||||
|
||||
switch entry.Metadata.Type {
|
||||
switch entry.Type {
|
||||
case stereoscopeFile.TypeSymLink, stereoscopeFile.TypeHardLink:
|
||||
// the location we are searching may be a symlink, we should always work with the resolved file
|
||||
locations, err := r.FilesByPath(location.RealPath)
|
||||
|
||||
@@ -59,7 +59,7 @@ func (r *Directory) buildIndex() error {
|
||||
|
||||
r.tree = tree
|
||||
r.index = index
|
||||
r.filetreeResolver.searchContext = filetree.NewSearchContext(tree, index)
|
||||
r.searchContext = filetree.NewSearchContext(tree, index)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (r *File) buildIndex() error {
|
||||
|
||||
r.tree = tree
|
||||
r.index = index
|
||||
r.filetreeResolver.searchContext = filetree.NewSearchContext(tree, index)
|
||||
r.searchContext = filetree.NewSearchContext(tree, index)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func (r filetreeResolver) FilesByPath(userPaths ...string) ([]file.Location, err
|
||||
}
|
||||
|
||||
// don't consider directories
|
||||
if entry.Metadata.IsDir() {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -114,17 +114,17 @@ func (r filetreeResolver) FilesByGlob(patterns ...string) ([]file.Location, erro
|
||||
}
|
||||
entry, err := r.index.Get(*refVia.Reference)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get file metadata for reference %s: %w", refVia.Reference.RealPath, err)
|
||||
return nil, fmt.Errorf("unable to get file metadata for reference %s: %w", refVia.RealPath, err)
|
||||
}
|
||||
|
||||
// don't consider directories
|
||||
if entry.Metadata.IsDir() {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
loc := file.NewVirtualLocationFromDirectory(
|
||||
r.responsePath(string(refVia.Reference.RealPath)), // the actual path relative to the resolver root
|
||||
r.responsePath(string(refVia.RequestPath)), // the path used to access this file, relative to the resolver root
|
||||
r.responsePath(string(refVia.RealPath)), // the actual path relative to the resolver root
|
||||
r.responsePath(string(refVia.RequestPath)), // the path used to access this file, relative to the resolver root
|
||||
*refVia.Reference,
|
||||
)
|
||||
uniqueFileIDs.Add(*refVia.Reference)
|
||||
@@ -217,7 +217,7 @@ func (r *filetreeResolver) FilesByMIMEType(types ...string) ([]file.Location, er
|
||||
continue
|
||||
}
|
||||
location := file.NewVirtualLocationFromDirectory(
|
||||
r.responsePath(string(refVia.Reference.RealPath)),
|
||||
r.responsePath(string(refVia.RealPath)),
|
||||
r.responsePath(string(refVia.RequestPath)),
|
||||
*refVia.Reference,
|
||||
)
|
||||
|
||||
@@ -25,6 +25,7 @@ func AllTypes() []any {
|
||||
pkg.ELFBinaryPackageNoteJSONPayload{},
|
||||
pkg.ElixirMixLockEntry{},
|
||||
pkg.ErlangRebarLockEntry{},
|
||||
pkg.GitHubActionsUseStatement{},
|
||||
pkg.GolangBinaryBuildinfoEntry{},
|
||||
pkg.GolangModuleEntry{},
|
||||
pkg.HackageStackYamlEntry{},
|
||||
|
||||
@@ -78,6 +78,7 @@ var jsonTypes = makeJSONTypes(
|
||||
jsonNames(pkg.DpkgDBEntry{}, "dpkg-db-entry", "DpkgMetadata"),
|
||||
jsonNames(pkg.ELFBinaryPackageNoteJSONPayload{}, "elf-binary-package-note-json-payload"),
|
||||
jsonNames(pkg.RubyGemspec{}, "ruby-gemspec", "GemMetadata"),
|
||||
jsonNames(pkg.GitHubActionsUseStatement{}, "github-actions-use-statement"),
|
||||
jsonNames(pkg.GolangBinaryBuildinfoEntry{}, "go-module-buildinfo-entry", "GolangBinMetadata", "GolangMetadata"),
|
||||
jsonNames(pkg.GolangModuleEntry{}, "go-module-entry", "GolangModMetadata"),
|
||||
jsonNames(pkg.HackageStackYamlLockEntry{}, "haskell-hackage-stack-lock-entry", "HackageMetadataType"),
|
||||
|
||||
@@ -123,7 +123,7 @@ func parseApkDB(_ context.Context, resolver file.Resolver, env *generic.Environm
|
||||
// This should get fixed with https://gitlab.alpinelinux.org/alpine/apk-tools/-/issues/10875
|
||||
if r == nil {
|
||||
// find the repositories file from the relative directory of the DB file
|
||||
releases := findReleases(resolver, reader.Location.RealPath)
|
||||
releases := findReleases(resolver, reader.RealPath)
|
||||
|
||||
if len(releases) > 0 {
|
||||
r = &releases[0]
|
||||
@@ -173,7 +173,7 @@ func parseReleasesFromAPKRepository(reader file.LocationReadCloser) []linux.Rele
|
||||
|
||||
reposB, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
log.Tracef("unable to read APK repositories file %q: %+v", reader.Location.RealPath, err)
|
||||
log.Tracef("unable to read APK repositories file %q: %+v", reader.RealPath, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ func parseAlpmDB(_ context.Context, resolver file.Resolver, env *generic.Environ
|
||||
newPackage(
|
||||
data,
|
||||
env.LinuxRelease,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
locs...,
|
||||
),
|
||||
}, nil, errs
|
||||
|
||||
@@ -699,6 +699,17 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
Metadata: metadata("go-binary-hint"),
|
||||
},
|
||||
},
|
||||
{
|
||||
// note: this is for compatability with dev version of golang tip image, which resolves the issue #3681
|
||||
logicalFixture: "go-version-hint/1.25/any",
|
||||
expected: pkg.Package{
|
||||
Name: "go",
|
||||
Version: "1.25-d524e1e",
|
||||
PURL: "pkg:generic/go@1.25-d524e1e",
|
||||
Locations: locations("VERSION.cache"),
|
||||
Metadata: metadata("go-binary-hint"),
|
||||
},
|
||||
},
|
||||
{
|
||||
// note: this is testing BUSYBOX which is typically through a link to "[" (in this case a symlink but in
|
||||
// practice this is often a hard link).
|
||||
@@ -1331,6 +1342,28 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
||||
Metadata: metadata("jq-binary"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "chrome/126.0.6478.182/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "chrome",
|
||||
Version: "126.0.6478.182",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/chrome@126.0.6478.182",
|
||||
Locations: locations("chrome"),
|
||||
Metadata: metadata("chrome-binary"),
|
||||
},
|
||||
},
|
||||
{
|
||||
logicalFixture: "chrome/127.0.6533.119/linux-amd64",
|
||||
expected: pkg.Package{
|
||||
Name: "chrome",
|
||||
Version: "127.0.6533.119",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/chrome@127.0.6533.119",
|
||||
Locations: locations("chrome"),
|
||||
Metadata: metadata("chrome-binary"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -171,9 +171,9 @@ func DefaultClassifiers() []Classifier {
|
||||
},
|
||||
{
|
||||
Class: "go-binary-hint",
|
||||
FileGlob: "**/VERSION",
|
||||
FileGlob: "**/VERSION*",
|
||||
EvidenceMatcher: FileContentsVersionMatcher(
|
||||
`(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?)`),
|
||||
`(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?(-[0-9a-f]{7})?)`),
|
||||
Package: "go",
|
||||
PURL: mustPURL("pkg:generic/go@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:golang:go:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
|
||||
@@ -670,6 +670,17 @@ func DefaultClassifiers() []Classifier {
|
||||
PURL: mustPURL("pkg:generic/jq@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:jqlang:jq:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
|
||||
},
|
||||
{
|
||||
Class: "chrome-binary",
|
||||
FileGlob: "**/chrome",
|
||||
EvidenceMatcher: FileContentsVersionMatcher(
|
||||
// [NUL]127.0.6533.119[NUL]Default
|
||||
`\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\x00Default`,
|
||||
),
|
||||
Package: "chrome",
|
||||
PURL: mustPURL("pkg:generic/chrome@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:google:chrome:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+2
@@ -0,0 +1,2 @@
|
||||
devel go1.25-d524e1e Sun Feb 16 07:23:13 2025 -0800
|
||||
3devel go1.25-d524e1e Sun Feb 16 07:23:13 2025 -0800
|
||||
@@ -130,6 +130,12 @@ from-images:
|
||||
paths:
|
||||
- /usr/local/go/bin/go
|
||||
|
||||
- version: 1.25
|
||||
images:
|
||||
- ref: golang:tip@sha256:319b219d4df413ef30123a7f69bdf00032d9841af58d7b0ef6971542b29875d5
|
||||
platform: linux/amd64
|
||||
paths:
|
||||
- /usr/local/go/bin/go
|
||||
# TODO: this is no longer available from dockerhub! (the snippet is vital)
|
||||
- version: 1.5.14
|
||||
images:
|
||||
|
||||
@@ -33,13 +33,13 @@ func parseSBOM(_ context.Context, resolver file.Resolver, _ *generic.Environment
|
||||
}
|
||||
|
||||
if s == nil {
|
||||
log.WithFields("path", reader.Location.RealPath).Trace("file is not an SBOM")
|
||||
log.WithFields("path", reader.RealPath).Trace("file is not an SBOM")
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
// Bitnami exclusively uses SPDX JSON SBOMs
|
||||
if sFormat != "spdx-json" {
|
||||
log.WithFields("path", reader.Location.RealPath).Trace("file is not an SPDX JSON SBOM")
|
||||
log.WithFields("path", reader.RealPath).Trace("file is not an SPDX JSON SBOM")
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func parseSBOM(_ context.Context, resolver file.Resolver, _ *generic.Environment
|
||||
// where there is evidence of this file, and the catalogers have not run against any file other than,
|
||||
// the SBOM, this is the only location that is relevant for this cataloger.
|
||||
p.Locations = file.NewLocationSet(
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
// Parse the Bitnami-specific metadata
|
||||
@@ -70,7 +70,7 @@ func parseSBOM(_ context.Context, resolver file.Resolver, _ *generic.Environment
|
||||
|
||||
// Bitnami packages reported in a SPDX file are shipped under the same directory
|
||||
// as the SPDX file itself.
|
||||
metadata.Path = filepath.Dir(reader.Location.RealPath)
|
||||
metadata.Path = filepath.Dir(reader.RealPath)
|
||||
if p.ID() != mainPkgID {
|
||||
metadata.Files = packageFiles(s.Relationships, p, metadata.Path)
|
||||
secondaryPkgsFiles = append(secondaryPkgsFiles, metadata.Files...)
|
||||
@@ -86,12 +86,12 @@ func parseSBOM(_ context.Context, resolver file.Resolver, _ *generic.Environment
|
||||
}
|
||||
|
||||
// Resolve all files owned by the main package in the SBOM and update the metadata
|
||||
if mainPkgFiles, err := mainPkgFiles(resolver, reader.Location.RealPath, secondaryPkgsFiles); err == nil {
|
||||
if mainPkgFiles, err := mainPkgFiles(resolver, reader.RealPath, secondaryPkgsFiles); err == nil {
|
||||
for i, p := range pkgs {
|
||||
if p.ID() == mainPkgID {
|
||||
metadata, ok := p.Metadata.(*pkg.BitnamiSBOMEntry)
|
||||
if !ok {
|
||||
log.WithFields("spdx-filepath", reader.Location.RealPath).Trace("main package in SBOM does not have Bitnami metadata")
|
||||
log.WithFields("spdx-filepath", reader.RealPath).Trace("main package in SBOM does not have Bitnami metadata")
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ func parseSBOM(_ context.Context, resolver file.Resolver, _ *generic.Environment
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.WithFields("spdx-filepath", reader.Location.RealPath, "error", err).Trace("unable to resolve owned files for main package in SBOM")
|
||||
log.WithFields("spdx-filepath", reader.RealPath, "error", err).Trace("unable to resolve owned files for main package in SBOM")
|
||||
}
|
||||
|
||||
return pkgs, filterRelationships(s.Relationships, pkgs), nil
|
||||
|
||||
@@ -48,7 +48,7 @@ func parseConanfile(_ context.Context, _ file.Resolver, _ *generic.Environment,
|
||||
|
||||
p := newConanfilePackage(
|
||||
m,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
if p == nil {
|
||||
continue
|
||||
|
||||
@@ -60,7 +60,7 @@ func parseFullRequiresLine(line string, reader file.LocationReadCloser, pkgs *[]
|
||||
|
||||
p := newConaninfoPackage(
|
||||
meta,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
if p != nil {
|
||||
*pkgs = append(*pkgs, *p)
|
||||
@@ -83,7 +83,7 @@ func parseConaninfo(_ context.Context, _ file.Resolver, _ *generic.Environment,
|
||||
// First set the base package info by checking the relative path
|
||||
fullFilePath := string(reader.Location.LocationData.Reference().RealPath)
|
||||
if len(fullFilePath) == 0 {
|
||||
fullFilePath = reader.Location.LocationData.RealPath
|
||||
fullFilePath = reader.RealPath
|
||||
}
|
||||
|
||||
mainMetadata, err := parseConanMetadataFromFilePath(fullFilePath)
|
||||
@@ -102,7 +102,7 @@ func parseConaninfo(_ context.Context, _ file.Resolver, _ *generic.Environment,
|
||||
case errors.Is(err, io.EOF):
|
||||
mainPackage := newConaninfoPackage(
|
||||
mainMetadata,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
mainPackageRef := *mainPackage
|
||||
|
||||
@@ -47,14 +47,14 @@ func parseConanLock(_ context.Context, _ file.Resolver, _ *generic.Environment,
|
||||
// in a second iteration
|
||||
var indexToPkgMap = map[string]pkg.Package{}
|
||||
|
||||
v1Pkgs := handleConanLockV2(cl, reader, indexToPkgMap)
|
||||
v2Pkgs := handleConanLockV2(cl, reader, indexToPkgMap)
|
||||
|
||||
// we do not want to store the index list requires in the conan metadata, because it is not useful to have it in
|
||||
// the SBOM. Instead, we will store it in a map and then use it to build the relationships
|
||||
// maps pkg.ID to a list of indices
|
||||
var parsedPkgRequires = map[artifact.ID][]string{}
|
||||
|
||||
v2Pkgs := handleConanLockV1(cl, reader, parsedPkgRequires, indexToPkgMap)
|
||||
v1Pkgs := handleConanLockV1(cl, reader, parsedPkgRequires, indexToPkgMap)
|
||||
|
||||
var relationships []artifact.Relationship
|
||||
var pkgs []pkg.Package
|
||||
@@ -91,7 +91,7 @@ func handleConanLockV1(cl conanLock, reader file.LocationReadCloser, parsedPkgRe
|
||||
|
||||
p := newConanlockPackage(
|
||||
metadata,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
if p != nil {
|
||||
@@ -115,7 +115,7 @@ func handleConanLockV2(cl conanLock, reader file.LocationReadCloser, indexToPkgM
|
||||
|
||||
p := newConanReferencePackage(
|
||||
reference,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
if p != nil {
|
||||
|
||||
@@ -102,7 +102,7 @@ func parsePubspecLock(_ context.Context, _ file.Resolver, _ *generic.Environment
|
||||
newPubspecLockPackage(
|
||||
name,
|
||||
pubPkg,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -288,7 +288,6 @@ func TestDpkgArchiveCataloger(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCataloger_Globs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -305,6 +304,9 @@ func TestCataloger_Globs(t *testing.T) {
|
||||
"var/lib/dpkg/status.d/pkg-1.0",
|
||||
"usr/lib/opkg/info/pkg-1.0.control",
|
||||
"usr/lib/opkg/status",
|
||||
"usr/lib/dpkg/info/libpam-runtime.conffiles",
|
||||
"usr/lib/dpkg/info/libpam-runtime.md5sums",
|
||||
"usr/share/doc/libpam-runtime/copyright",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func parseDpkgDB(ctx context.Context, resolver file.Resolver, env *generic.Envir
|
||||
return nil, nil, fmt.Errorf("unable to catalog dpkg DB=%q: %w", reader.RealPath, err)
|
||||
}
|
||||
|
||||
dbLoc := reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)
|
||||
dbLoc := reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)
|
||||
var pkgs []pkg.Package
|
||||
_ = sync.CollectSlice(&ctx, cataloging.ExecutorFile, sync.ToSeq(metadata), func(m pkg.DpkgDBEntry) (pkg.Package, error) {
|
||||
return newDpkgPackage(m, dbLoc, resolver, env.LinuxRelease, findDpkgInfoFiles(m.Package, resolver, reader.Location)...), nil
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
/etc/pam.conf
|
||||
/etc/pam.d/other
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
55f905631797551d4d936a34c7e73474 lib/x86_64-linux-gnu/libz.so.1.2.11
|
||||
cede84bda30d2380217f97753c8ccf3a usr/share/doc/zlib1g/changelog.Debian.gz
|
||||
f3c9dafa6da7992c47328b4464f6d122 usr/share/doc/zlib1g/changelog.gz
|
||||
a4fae96070439a5209a62ae5b8017ab2 usr/share/doc/zlib1g/copyright
|
||||
+1
@@ -0,0 +1 @@
|
||||
# some shell script...
|
||||
@@ -1 +1,23 @@
|
||||
bogus status
|
||||
Package:
|
||||
|
||||
Package: libpam-runtime
|
||||
Status: install ok installed
|
||||
Priority: required
|
||||
Section: admin
|
||||
Installed-Size: 1016
|
||||
Maintainer: Steve Langasek <vorlon@debian.org>
|
||||
Architecture: all
|
||||
Multi-Arch: foreign
|
||||
Source: pam
|
||||
Version: 1.1.8-3.6
|
||||
Replaces: libpam0g-dev, libpam0g-util
|
||||
Depends: debconf (>= 0.5) | debconf-2.0, debconf (>= 1.5.19) | cdebconf, libpam-modules (>= 1.0.1-6)
|
||||
Conflicts: libpam0g-util
|
||||
Conffiles:
|
||||
/etc/pam.conf 87fc76f18e98ee7d3848f6b81b3391e5
|
||||
/etc/pam.d/other 31aa7f2181889ffb00b87df4126d1701
|
||||
Description: Runtime support for the PAM library
|
||||
Contains configuration files and directories required for
|
||||
authentication to work on Debian systems. This package is required
|
||||
on almost all installations.
|
||||
Homepage: http://www.linux-pam.org/
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: auditd
|
||||
Source: https://people.redhat.com/sgrubb/audit/
|
||||
|
||||
Files: *
|
||||
Copyright: 2012-2016 Steve Grubb <sgrubb@redhat.com>
|
||||
2006-2012 Rik Faith
|
||||
License: GPL-2
|
||||
|
||||
Files: src/libev/*
|
||||
Copyright: 2007-2009 Marc Alexamder Lehmann
|
||||
License: GPL-2
|
||||
|
||||
Files: lib/*
|
||||
Copyright: 2005-2008 Steve Grubb <sgrubb@redhat.com>
|
||||
License: LGPL-2.1
|
||||
The audit daemon's library libaudit.* is released under LGPL
|
||||
so that it may be linked with 3rd party software.
|
||||
.
|
||||
On Debian systems, refer to /usr/share/common-licenses/LGPL-2.1
|
||||
for the complete text of the GNU Lesser General Public License.
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2007-2011 Philipp Matthias Hahn <pmhahn@debian.org>
|
||||
2012-2016 Laurent Bigonville <bigon@debian.org>
|
||||
License: GPL-2
|
||||
|
||||
License: GPL-2
|
||||
This package is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2,
|
||||
as published by the Free Software Foundation.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this package; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/GPL-1'.
|
||||
@@ -1,9 +1,9 @@
|
||||
package dotnet
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
@@ -119,6 +119,10 @@ func TestCataloger(t *testing.T) {
|
||||
}
|
||||
net8AppExpectedDepPkgs = append(net8AppExpectedDepPkgs, net8AppExpectedDepPkgsWithoutUnpairedDlls...)
|
||||
|
||||
var net8AppExpectedDepPkgsWithRuntime []string
|
||||
net8AppExpectedDepPkgsWithRuntime = append(net8AppExpectedDepPkgsWithRuntime, net8AppExpectedDepPkgs...)
|
||||
net8AppExpectedDepPkgsWithRuntime = append(net8AppExpectedDepPkgsWithRuntime, "Microsoft.NETCore.App.Runtime.linux-x64 @ 8.0.14 (/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.14/Microsoft.NETCore.App.deps.json)")
|
||||
|
||||
// app binaries (always dlls)
|
||||
net8AppBinaryOnlyPkgs := []string{
|
||||
"Humanizer @ 2.14.1.48190 (/app/Humanizer.dll)",
|
||||
@@ -280,11 +284,17 @@ func TestCataloger(t *testing.T) {
|
||||
net8AppDepOnlyRelationships = append(net8AppDepOnlyRelationships, net8AppDepOnlyRelationshipsWithoutHumanizer...)
|
||||
net8AppDepOnlyRelationships = append(net8AppDepOnlyRelationships, humanizerToAppDepsRelationship)
|
||||
|
||||
var net8AppDepOnlyRelationshipsWithRuntime []string
|
||||
net8AppDepOnlyRelationshipsWithRuntime = append(net8AppDepOnlyRelationshipsWithRuntime, net8AppDepOnlyRelationships...)
|
||||
net8AppDepOnlyRelationshipsWithRuntime = append(net8AppDepOnlyRelationshipsWithRuntime,
|
||||
"Microsoft.NETCore.App.Runtime.linux-x64 @ 8.0.14 (/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.14/Microsoft.NETCore.App.deps.json) [dependency-of] dotnetapp @ 1.0.0 (/app/dotnetapp.deps.json)",
|
||||
)
|
||||
|
||||
var net8AppExpectedDepRelationships []string
|
||||
net8AppExpectedDepRelationships = append(net8AppExpectedDepRelationships, net8AppDepOnlyRelationships...)
|
||||
|
||||
var net8AppExpectedDepSelfContainedPkgs []string
|
||||
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs, net8AppExpectedDepPkgsWithoutUnpairedDlls...)
|
||||
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs, net8AppExpectedDepPkgs...)
|
||||
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs,
|
||||
// add the CLR runtime packages...
|
||||
"runtimepack.Microsoft.NETCore.App.Runtime.win-x64 @ 8.0.14 (/app/dotnetapp.deps.json)",
|
||||
@@ -298,7 +308,7 @@ func TestCataloger(t *testing.T) {
|
||||
)
|
||||
|
||||
var net8AppExpectedDepSelfContainedRelationships []string
|
||||
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships, net8AppDepOnlyRelationshipsWithoutHumanizer...)
|
||||
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships, net8AppDepOnlyRelationships...)
|
||||
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships,
|
||||
// add the CLR runtime relationships...
|
||||
"runtimepack.Microsoft.NETCore.App.Runtime.win-x64 @ 8.0.14 (/app/dotnetapp.deps.json) [dependency-of] dotnetapp @ 1.0.0 (/app/dotnetapp.deps.json)",
|
||||
@@ -706,36 +716,20 @@ func TestCataloger(t *testing.T) {
|
||||
assertion: assertAllDepEntriesWithoutExecutables,
|
||||
},
|
||||
{
|
||||
name: "combined cataloger",
|
||||
fixture: "image-net8-app",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
|
||||
// if we don't care about DLL claims in the deps.json, then this is right
|
||||
//expectedPkgs: net8AppExpectedDepPkgs,
|
||||
//expectedRels: net8AppExpectedDepRelationships,
|
||||
|
||||
// we care about DLL claims in the deps.json, so the main application inherits all relationships to/from humanizer
|
||||
expectedPkgs: net8AppExpectedDepPkgsWithoutUnpairedDlls,
|
||||
expectedRels: replaceAll(net8AppDepOnlyRelationshipsWithoutHumanizer, "Humanizer @ 2.14.1", "dotnetapp @ 1.0.0"),
|
||||
|
||||
assertion: assertAlmostAllDepEntriesWithExecutables, // important! this is what makes this case different from the previous one... dep entries have attached executables
|
||||
name: "combined cataloger",
|
||||
fixture: "image-net8-app",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
expectedPkgs: net8AppExpectedDepPkgs,
|
||||
expectedRels: net8AppDepOnlyRelationships,
|
||||
assertion: assertAlmostAllDepEntriesWithExecutables, // important! this is what makes this case different from the previous one... dep entries have attached executables
|
||||
},
|
||||
{
|
||||
name: "combined cataloger (with runtime)",
|
||||
fixture: "image-net8-app-with-runtime",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
expectedPkgs: func() []string {
|
||||
pkgs := net8AppExpectedDepPkgsWithoutUnpairedDlls
|
||||
pkgs = append(pkgs, "Microsoft.NETCore.App.Runtime.linux-x64 @ 8.0.14 (/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.14/Microsoft.NETCore.App.deps.json)")
|
||||
return pkgs
|
||||
}(),
|
||||
expectedRels: func() []string {
|
||||
x := replaceAll(net8AppDepOnlyRelationshipsWithoutHumanizer, "Humanizer @ 2.14.1", "dotnetapp @ 1.0.0")
|
||||
// the main application should also have a relationship to the runtime package
|
||||
x = append(x, "Microsoft.NETCore.App.Runtime.linux-x64 @ 8.0.14 (/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.14/Microsoft.NETCore.App.deps.json) [dependency-of] dotnetapp @ 1.0.0 (/app/dotnetapp.deps.json)")
|
||||
return x
|
||||
}(),
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
name: "combined cataloger (with runtime)",
|
||||
fixture: "image-net8-app-with-runtime",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
expectedPkgs: net8AppExpectedDepPkgsWithRuntime,
|
||||
expectedRels: net8AppDepOnlyRelationshipsWithRuntime,
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
},
|
||||
{
|
||||
name: "combined cataloger (with runtime, no deps.json anywhere)",
|
||||
@@ -923,11 +917,7 @@ func TestCataloger(t *testing.T) {
|
||||
fixture: "image-net8-app-self-contained",
|
||||
cataloger: NewDotnetDepsCataloger(),
|
||||
expectedPkgs: net8AppExpectedDepsSelfContainedPkgs,
|
||||
expectedRels: func() []string {
|
||||
x := net8AppExpectedDepSelfContainedRelationships
|
||||
x = append(x, humanizerToAppDepsRelationship)
|
||||
return x
|
||||
}(),
|
||||
expectedRels: net8AppExpectedDepSelfContainedRelationships,
|
||||
},
|
||||
{
|
||||
name: "combined cataloger (self-contained)",
|
||||
@@ -935,13 +925,8 @@ func TestCataloger(t *testing.T) {
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
// we care about DLL claims in the deps.json, so the main application inherits all relationships to/from humarizer
|
||||
expectedPkgs: net8AppExpectedDepSelfContainedPkgs,
|
||||
expectedRels: func() []string {
|
||||
x := replaceAll(net8AppExpectedDepSelfContainedRelationships, "Humanizer @ 2.14.1", "dotnetapp @ 1.0.0")
|
||||
// the main application also has a dependency on the runtime package
|
||||
x = append(x, "runtimepack.Microsoft.NETCore.App.Runtime.win-x64 @ 8.0.14 (/app/dotnetapp.deps.json) [dependency-of] dotnetapp @ 1.0.0 (/app/dotnetapp.deps.json)")
|
||||
return x
|
||||
}(),
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
expectedRels: net8AppExpectedDepSelfContainedRelationships,
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
},
|
||||
{
|
||||
name: "pe cataloger (self-contained)",
|
||||
@@ -1004,19 +989,37 @@ func TestCataloger(t *testing.T) {
|
||||
fixture: "image-net2-app",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
expectedPkgs: []string{
|
||||
"Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
"Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
"Serilog @ 2.10.0 (/app/helloworld.deps.json)",
|
||||
"Serilog.Sinks.Console @ 4.0.1 (/app/helloworld.deps.json)",
|
||||
"helloworld @ 1.0.0 (/app/helloworld.deps.json)",
|
||||
"runtime.linux-x64.Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
"runtime.linux-x64.Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)", // a compile target reference
|
||||
},
|
||||
expectedRels: []string{
|
||||
"Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
"Serilog @ 2.10.0 (/app/helloworld.deps.json) [dependency-of] Serilog.Sinks.Console @ 4.0.1 (/app/helloworld.deps.json)",
|
||||
"Serilog @ 2.10.0 (/app/helloworld.deps.json) [dependency-of] helloworld @ 1.0.0 (/app/helloworld.deps.json)",
|
||||
"Serilog.Sinks.Console @ 4.0.1 (/app/helloworld.deps.json) [dependency-of] helloworld @ 1.0.0 (/app/helloworld.deps.json)",
|
||||
"runtime.linux-x64.Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
"runtime.linux-x64.Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] helloworld @ 1.0.0 (/app/helloworld.deps.json)",
|
||||
"runtime.linux-x64.Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
},
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
},
|
||||
{
|
||||
name: "libman support",
|
||||
fixture: "image-net6-asp-libman",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
expectedPkgs: []string{
|
||||
"LibManSample @ 1.0.0 (/app/LibManSample.deps.json)",
|
||||
"jquery @ 3.3.1 (/app/libman.json)",
|
||||
},
|
||||
expectedRels: []string{
|
||||
"jquery @ 3.3.1 (/app/libman.json) [dependency-of] LibManSample @ 1.0.0 (/app/LibManSample.deps.json)",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
@@ -1035,7 +1038,26 @@ func TestCataloger(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDotnetDepsCataloger_problemCases(t *testing.T) {
|
||||
func TestDotnetDepsCataloger_regressions(t *testing.T) {
|
||||
|
||||
assertPackages := func(mustHave []string, mustNotHave []string) func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
|
||||
expected := strset.New(mustHave...)
|
||||
notExpected := strset.New(mustNotHave...)
|
||||
return func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
|
||||
|
||||
for _, p := range pkgs {
|
||||
expected.Remove(p.Name)
|
||||
if notExpected.Has(p.Name) {
|
||||
t.Errorf("unexpected package: %s", p.Name)
|
||||
}
|
||||
}
|
||||
if expected.IsEmpty() {
|
||||
return
|
||||
}
|
||||
t.Errorf("missing packages: %s", expected.List())
|
||||
}
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
fixture string
|
||||
@@ -1072,6 +1094,72 @@ func TestDotnetDepsCataloger_problemCases(t *testing.T) {
|
||||
pkgtest.AssertPackagesEqualIgnoreLayers(t, expected, actual)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "indirect packages references",
|
||||
fixture: "image-net8-compile-target",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
assertion: assertPackages(
|
||||
[]string{
|
||||
"DotNetNuke.Core", // uses a compile target reference in the deps.json
|
||||
"Umbraco.Cms", // this is the parent of other packages which do have DLLs included (even though it does not have any DLLs)
|
||||
},
|
||||
[]string{
|
||||
"StyleCop.Analyzers", // this is a development tool
|
||||
"Microsoft.NET.Test.Sdk", // this is a development tool
|
||||
"jQuery", // has no DLLs but has javascript assets
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "not propagating claims",
|
||||
fixture: "image-net8-compile-target",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig().WithPropagateDLLClaimsToParents(false)),
|
||||
assertion: assertPackages(
|
||||
[]string{
|
||||
"DotNetNuke.Core", // uses a compile target reference in the deps.json
|
||||
|
||||
},
|
||||
[]string{
|
||||
"Umbraco.Cms", // this is the parent of other packages which do have DLLs included (even though it does not have any DLLs)
|
||||
"StyleCop.Analyzers", // this is a development tool
|
||||
"Microsoft.NET.Test.Sdk", // this is a development tool under the debug configuration (we build the release configuration)
|
||||
"jQuery", // has no DLLs but has javascript assets -- this is bad behavior (as we want to detect this)
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "not requiring claims finds jquery",
|
||||
fixture: "image-net8-compile-target",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(CatalogerConfig{
|
||||
DepPackagesMustHaveDLL: false,
|
||||
DepPackagesMustClaimDLL: false,
|
||||
PropagateDLLClaimsToParents: false,
|
||||
RelaxDLLClaimsWhenBundlingDetected: false,
|
||||
}),
|
||||
assertion: assertPackages(
|
||||
[]string{
|
||||
"jQuery", // has no DLLs but has javascript assets
|
||||
"StyleCop.Analyzers", // this is a development tool -- this is bad behavior (since we should not detect this), but cannot be helped
|
||||
},
|
||||
[]string{
|
||||
"Microsoft.NET.Test.Sdk", // this is a development tool under the debug configuration (we build the release configuration)
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "libman support",
|
||||
fixture: "image-net6-asp-libman",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
assertion: assertPackages(
|
||||
[]string{
|
||||
"jquery", // a javascript package, not the nuget package
|
||||
},
|
||||
[]string{
|
||||
"vendor", // this is the string reference for a filesystem provider
|
||||
"lodash", // this is from a filesystem provider, which is not supported
|
||||
},
|
||||
),
|
||||
},
|
||||
}
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -1460,11 +1548,3 @@ func extractMatchingPackage(t *testing.T, name string, pkgs []pkg.Package) pkg.P
|
||||
t.Fatalf("expected to find package %s", name)
|
||||
return pkg.Package{}
|
||||
}
|
||||
|
||||
func replaceAll(ss []string, find, replace string) []string {
|
||||
var results []string
|
||||
for _, s := range ss {
|
||||
results = append(results, strings.ReplaceAll(s, find, replace))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ type CatalogerConfig struct {
|
||||
// This does not require such claimed DLLs to exist on disk. The behavior of this
|
||||
DepPackagesMustClaimDLL bool `mapstructure:"dep-packages-must-claim-dll" json:"dep-packages-must-claim-dll" yaml:"dep-packages-must-claim-dll"`
|
||||
|
||||
// PropagateDLLClaimsToParents allows for deps.json packages to be included if any child (transitive) package claims a DLL. This applies to both the claims configuration and evidence-on-disk configurations.
|
||||
PropagateDLLClaimsToParents bool `mapstructure:"propagate-dll-claims-to-parents" json:"propagate-dll-claims-to-parents" yaml:"propagate-dll-claims-to-parents"`
|
||||
|
||||
// RelaxDLLClaimsWhenBundlingDetected will look for indications of IL bundle tooling via deps.json package names
|
||||
// and, if found (and this config option is enabled), will relax the DepPackagesMustClaimDLL value to `false` only in those cases.
|
||||
RelaxDLLClaimsWhenBundlingDetected bool `mapstructure:"relax-dll-claims-when-bundling-detected" json:"relax-dll-claims-when-bundling-detected" yaml:"relax-dll-claims-when-bundling-detected"`
|
||||
@@ -28,10 +31,16 @@ func (c CatalogerConfig) WithRelaxDLLClaimsWhenBundlingDetected(relax bool) Cata
|
||||
return c
|
||||
}
|
||||
|
||||
func (c CatalogerConfig) WithPropagateDLLClaimsToParents(propagate bool) CatalogerConfig {
|
||||
c.PropagateDLLClaimsToParents = propagate
|
||||
return c
|
||||
}
|
||||
|
||||
func DefaultCatalogerConfig() CatalogerConfig {
|
||||
return CatalogerConfig{
|
||||
DepPackagesMustHaveDLL: false,
|
||||
DepPackagesMustClaimDLL: true,
|
||||
PropagateDLLClaimsToParents: true,
|
||||
RelaxDLLClaimsWhenBundlingDetected: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,9 @@ func (c depsBinaryCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
||||
var runtimePkgs []*pkg.Package
|
||||
for i := range pkgs {
|
||||
p := &pkgs[i]
|
||||
if p.Type != pkg.DotnetPkg {
|
||||
continue
|
||||
}
|
||||
if isRuntime(p.Name) {
|
||||
existingRuntimeVersions.Add(p.Version)
|
||||
runtimePkgs = append(runtimePkgs, p)
|
||||
@@ -111,7 +114,7 @@ func (c depsBinaryCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
||||
runtimePkgs = append(runtimePkgs, &rtp)
|
||||
}
|
||||
|
||||
// create a relationship from every runtime package to every root package
|
||||
// create a relationship from every runtime package to every root package...
|
||||
for _, root := range roots {
|
||||
for _, runtimePkg := range runtimePkgs {
|
||||
relationships = append(relationships, artifact.Relationship{
|
||||
@@ -122,7 +125,8 @@ func (c depsBinaryCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
||||
}
|
||||
}
|
||||
|
||||
return pkgs, relationships, unknowns
|
||||
// in the process of creating root-to-runtime relationships, we may have created duplicate relationships. Use the relationship index to deduplicate.
|
||||
return pkgs, relationship.NewIndex(relationships...).All(), unknowns
|
||||
}
|
||||
|
||||
var runtimeDLLPathPattern = regexp.MustCompile(`/Microsoft\.NETCore\.App/(?P<version>\d+\.\d+\.\d+)/[^/]+\.dll`)
|
||||
@@ -204,6 +208,14 @@ func attachAssociatedExecutables(dep *logicalDepsJSON, pe logicalPE) bool {
|
||||
continue
|
||||
}
|
||||
|
||||
if targetPath, ok := p.CompilePathsByRelativeDLLPath[relativeDllPath]; ok {
|
||||
pe.TargetPath = targetPath
|
||||
p.Executables = append(p.Executables, pe)
|
||||
dep.PackagesByNameVersion[key] = p // update the map with the modified package
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
|
||||
if p.NativePaths.Has(relativeDllPath) {
|
||||
pe.TargetPath = relativeDllPath
|
||||
p.Executables = append(p.Executables, pe)
|
||||
@@ -259,15 +271,14 @@ func packagesFromLogicalDepsJSON(doc logicalDepsJSON, config CatalogerConfig) (*
|
||||
continue
|
||||
}
|
||||
lp := doc.PackagesByNameVersion[nameVersion]
|
||||
if config.DepPackagesMustHaveDLL && len(lp.Executables) == 0 {
|
||||
if config.DepPackagesMustHaveDLL && !lp.FoundDLLs(config.PropagateDLLClaimsToParents) {
|
||||
// could not find a paired DLL and the user required this...
|
||||
skippedDepPkgs[nameVersion] = lp
|
||||
continue
|
||||
}
|
||||
|
||||
claimsDLLs := len(lp.RuntimePathsByRelativeDLLPath) > 0 || len(lp.ResourcePathsByRelativeDLLPath) > 0
|
||||
|
||||
if config.DepPackagesMustClaimDLL && !claimsDLLs {
|
||||
// check to see if we should skip this package because it does not claim a DLL (or has not dependency that claims a DLL)
|
||||
if config.DepPackagesMustClaimDLL && !lp.ClaimsDLLs(config.PropagateDLLClaimsToParents) {
|
||||
if config.RelaxDLLClaimsWhenBundlingDetected && !doc.BundlingDetected || !config.RelaxDLLClaimsWhenBundlingDetected {
|
||||
// could not find a runtime or resource path and the user required this...
|
||||
// and there is no evidence of a bundler in the dependencies (e.g. ILRepack)
|
||||
@@ -282,8 +293,22 @@ func packagesFromLogicalDepsJSON(doc logicalDepsJSON, config CatalogerConfig) (*
|
||||
pkgMap[nameVersion] = *dotnetPkg
|
||||
}
|
||||
}
|
||||
rels := relationshipsFromLogicalDepsJSON(doc, pkgMap, skippedDepPkgs)
|
||||
|
||||
return rootPkg, pkgs, relationshipsFromLogicalDepsJSON(doc, pkgMap, skippedDepPkgs)
|
||||
// ensure that any libman packages are associated with the all root packages
|
||||
for _, libmanPkg := range doc.LibmanPackages {
|
||||
pkgs = append(pkgs, libmanPkg)
|
||||
if rootPkg == nil {
|
||||
continue
|
||||
}
|
||||
rels = append(rels, artifact.Relationship{
|
||||
From: libmanPkg,
|
||||
To: *rootPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
})
|
||||
}
|
||||
|
||||
return rootPkg, pkgs, rels
|
||||
}
|
||||
|
||||
// relationshipsFromLogicalDepsJSON creates relationships from a logicalDepsJSON document for only the given syft packages.
|
||||
@@ -381,7 +406,13 @@ func findDepsJSON(resolver file.Resolver) ([]logicalDepsJSON, error, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
depsJSONs = append(depsJSONs, getLogicalDepsJSON(*dj))
|
||||
libman, err := findLibmanJSON(resolver, loc)
|
||||
if err != nil {
|
||||
unknownErr = unknown.Append(unknownErr, loc, err)
|
||||
libman = nil
|
||||
}
|
||||
|
||||
depsJSONs = append(depsJSONs, getLogicalDepsJSON(*dj, libman))
|
||||
}
|
||||
|
||||
return depsJSONs, unknownErr, nil
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
type depsJSON struct {
|
||||
@@ -26,9 +27,50 @@ type depsTarget struct {
|
||||
Dependencies map[string]string `json:"dependencies"`
|
||||
Runtime map[string]map[string]string `json:"runtime"`
|
||||
Resources map[string]map[string]string `json:"resources"`
|
||||
Compile map[string]map[string]string `json:"compile"`
|
||||
Native map[string]map[string]string `json:"native"`
|
||||
}
|
||||
|
||||
func (t depsTarget) nativePaths() *strset.Set {
|
||||
results := strset.New()
|
||||
for path := range t.Native {
|
||||
results.Add(path)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func (t depsTarget) compilePaths() map[string]string {
|
||||
result := make(map[string]string)
|
||||
for path := range t.Compile {
|
||||
trimmedPath := trimLibPrefix(path)
|
||||
if _, exists := result[trimmedPath]; exists {
|
||||
continue
|
||||
}
|
||||
result[trimmedPath] = path
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (t depsTarget) resourcePaths() map[string]string {
|
||||
result := make(map[string]string)
|
||||
for path := range t.Resources {
|
||||
trimmedPath := trimLibPrefix(path)
|
||||
if _, exists := result[trimmedPath]; exists {
|
||||
continue
|
||||
}
|
||||
result[trimmedPath] = path
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (t depsTarget) runtimePaths() map[string]string {
|
||||
result := make(map[string]string)
|
||||
for path := range t.Runtime {
|
||||
result[trimLibPrefix(path)] = path
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type depsLibrary struct {
|
||||
Type string `json:"type"`
|
||||
Path string `json:"path"`
|
||||
@@ -43,6 +85,12 @@ type logicalDepsJSONPackage struct {
|
||||
Targets *depsTarget
|
||||
Library *depsLibrary
|
||||
|
||||
// anyChildClaimsDLLs is a flag that indicates if any of the children of this package claim a DLL associated with them in the deps.json.
|
||||
anyChildClaimsDLLs bool
|
||||
|
||||
// anyChildHasDLLs is a flag that indicates if any of the children of this package have a DLL associated with them (found on disk).
|
||||
anyChildHasDLLs bool
|
||||
|
||||
// RuntimePathsByRelativeDLLPath is a map of the relative path to the DLL relative to the deps.json file
|
||||
// to the target path as described in the deps.json target entry under "runtime".
|
||||
RuntimePathsByRelativeDLLPath map[string]string
|
||||
@@ -51,6 +99,10 @@ type logicalDepsJSONPackage struct {
|
||||
// to the target path as described in the deps.json target entry under "resource".
|
||||
ResourcePathsByRelativeDLLPath map[string]string
|
||||
|
||||
// CompilePathsByRelativeDLLPath is a map of the relative path to the DLL relative to the deps.json file
|
||||
// to the target path as described in the deps.json target entry under "compile".
|
||||
CompilePathsByRelativeDLLPath map[string]string
|
||||
|
||||
// NativePathsByRelativeDLLPath is a map of the relative path to the DLL relative to the deps.json file
|
||||
// to the target path as described in the deps.json target entry under "native". These should not have
|
||||
// any runtime references to trim from the front of the path.
|
||||
@@ -62,12 +114,41 @@ type logicalDepsJSONPackage struct {
|
||||
Executables []logicalPE
|
||||
}
|
||||
|
||||
func (l *logicalDepsJSONPackage) dependencyNameVersions() []string {
|
||||
if l.Targets == nil {
|
||||
return nil
|
||||
}
|
||||
var results []string
|
||||
for name, version := range l.Targets.Dependencies {
|
||||
results = append(results, createNameAndVersion(name, version))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// ClaimsDLLs indicates if this package has any DLLs associated with it (directly or indirectly with a dependency).
|
||||
func (l *logicalDepsJSONPackage) ClaimsDLLs(includeChildren bool) bool {
|
||||
selfClaim := len(l.RuntimePathsByRelativeDLLPath) > 0 || len(l.ResourcePathsByRelativeDLLPath) > 0 || len(l.CompilePathsByRelativeDLLPath) > 0 || len(l.NativePaths.List()) > 0
|
||||
if !includeChildren {
|
||||
return selfClaim
|
||||
}
|
||||
return selfClaim || l.anyChildClaimsDLLs
|
||||
}
|
||||
|
||||
func (l *logicalDepsJSONPackage) FoundDLLs(includeChildren bool) bool {
|
||||
selfClaim := len(l.Executables) > 0
|
||||
if !includeChildren {
|
||||
return selfClaim
|
||||
}
|
||||
return selfClaim || l.anyChildHasDLLs
|
||||
}
|
||||
|
||||
type logicalDepsJSON struct {
|
||||
Location file.Location
|
||||
RuntimeTarget runtimeTarget
|
||||
PackagesByNameVersion map[string]logicalDepsJSONPackage
|
||||
PackageNameVersions *strset.Set
|
||||
BundlingDetected bool
|
||||
LibmanPackages []pkg.Package
|
||||
}
|
||||
|
||||
func (l logicalDepsJSON) RootPackage() (logicalDepsJSONPackage, bool) {
|
||||
@@ -117,7 +198,7 @@ var knownBundlers = strset.New(
|
||||
"Fody", // IL weaving framework
|
||||
)
|
||||
|
||||
func getLogicalDepsJSON(deps depsJSON) logicalDepsJSON {
|
||||
func getLogicalDepsJSON(deps depsJSON, lm *libmanJSON) logicalDepsJSON {
|
||||
packageMap := make(map[string]*logicalDepsJSONPackage)
|
||||
nameVersions := strset.New()
|
||||
|
||||
@@ -133,31 +214,15 @@ func getLogicalDepsJSON(deps depsJSON) logicalDepsJSON {
|
||||
if ok {
|
||||
lib = &l
|
||||
}
|
||||
runtimePaths := make(map[string]string)
|
||||
for path := range target.Runtime {
|
||||
runtimePaths[trimLibPrefix(path)] = path
|
||||
}
|
||||
resourcePaths := make(map[string]string)
|
||||
for path := range target.Resources {
|
||||
trimmedPath := trimLibPrefix(path)
|
||||
if _, exists := resourcePaths[trimmedPath]; exists {
|
||||
continue
|
||||
}
|
||||
resourcePaths[trimmedPath] = path
|
||||
}
|
||||
|
||||
nativePaths := strset.New()
|
||||
for path := range target.Native {
|
||||
nativePaths.Add(path)
|
||||
}
|
||||
|
||||
p := &logicalDepsJSONPackage{
|
||||
NameVersion: libName,
|
||||
Library: lib,
|
||||
Targets: &target,
|
||||
RuntimePathsByRelativeDLLPath: runtimePaths,
|
||||
ResourcePathsByRelativeDLLPath: resourcePaths,
|
||||
NativePaths: nativePaths,
|
||||
RuntimePathsByRelativeDLLPath: target.runtimePaths(),
|
||||
ResourcePathsByRelativeDLLPath: target.resourcePaths(),
|
||||
CompilePathsByRelativeDLLPath: target.compilePaths(),
|
||||
NativePaths: target.nativePaths(),
|
||||
}
|
||||
packageMap[libName] = p
|
||||
nameVersions.Add(libName)
|
||||
@@ -170,6 +235,8 @@ func getLogicalDepsJSON(deps depsJSON) logicalDepsJSON {
|
||||
if !bundlingDetected && knownBundlers.Has(name) {
|
||||
bundlingDetected = true
|
||||
}
|
||||
p.anyChildClaimsDLLs = searchForDLLClaims(packageMap, p.dependencyNameVersions()...)
|
||||
p.anyChildHasDLLs = searchForDLLEvidence(packageMap, p.dependencyNameVersions()...)
|
||||
packages[p.NameVersion] = *p
|
||||
}
|
||||
|
||||
@@ -179,9 +246,51 @@ func getLogicalDepsJSON(deps depsJSON) logicalDepsJSON {
|
||||
PackagesByNameVersion: packages,
|
||||
PackageNameVersions: nameVersions,
|
||||
BundlingDetected: bundlingDetected,
|
||||
LibmanPackages: lm.packages(),
|
||||
}
|
||||
}
|
||||
|
||||
type visitorFunc func(p *logicalDepsJSONPackage) bool
|
||||
|
||||
// searchForDLLEvidence recursively searches for executables found for any of the given nameVersions and children recursively.
|
||||
func searchForDLLEvidence(packageMap map[string]*logicalDepsJSONPackage, nameVersions ...string) bool {
|
||||
return traverseDependencies(packageMap, func(p *logicalDepsJSONPackage) bool {
|
||||
return p.FoundDLLs(true)
|
||||
}, nameVersions...)
|
||||
}
|
||||
|
||||
// searchForDLLClaims recursively searches for DLL claims in the deps.json for any of the given nameVersions and children recursively.
|
||||
func searchForDLLClaims(packageMap map[string]*logicalDepsJSONPackage, nameVersions ...string) bool {
|
||||
return traverseDependencies(packageMap, func(p *logicalDepsJSONPackage) bool {
|
||||
return p.ClaimsDLLs(true)
|
||||
}, nameVersions...)
|
||||
}
|
||||
|
||||
func traverseDependencies(packageMap map[string]*logicalDepsJSONPackage, visitor visitorFunc, nameVersions ...string) bool {
|
||||
if len(nameVersions) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, nameVersion := range nameVersions {
|
||||
if p, ok := packageMap[nameVersion]; ok {
|
||||
if visitor(p) {
|
||||
return true
|
||||
}
|
||||
|
||||
var children []string
|
||||
for name, version := range p.Targets.Dependencies {
|
||||
children = append(children, createNameAndVersion(name, version))
|
||||
}
|
||||
|
||||
if traverseDependencies(packageMap, visitor, children...) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var libPathPattern = regexp.MustCompile(`^(?:runtimes/[^/]+/)?lib/net[^/]+/(?P<targetPath>.+)`)
|
||||
|
||||
// trimLibPrefix removes prefixes like "lib/net6.0/" or "runtimes/linux-arm/lib/netcoreapp2.2/" from a path.
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package dotnet
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
// libmanJSON represents the libman.json file format in ASP.NET projects for describing javascript assets to be downloaded and bundled
|
||||
// see https://github.com/aspnet/LibraryManager/wiki/libman.json-reference
|
||||
type libmanJSON struct {
|
||||
Location file.Location `json:"-"`
|
||||
Version string `json:"version"`
|
||||
DefaultProvider string `json:"defaultProvider"`
|
||||
Libraries []struct {
|
||||
Library string `json:"library"`
|
||||
Files []string `json:"files"`
|
||||
Destination string `json:"destination"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
} `json:"libraries"`
|
||||
}
|
||||
|
||||
func (l *libmanJSON) packages() []pkg.Package {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var pkgs []pkg.Package
|
||||
for _, lib := range l.Libraries {
|
||||
if lib.Provider == "filesystem" {
|
||||
// there is no name and version with filesystem providers
|
||||
continue
|
||||
}
|
||||
fields := strings.Split(lib.Library, "@")
|
||||
if len(fields) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
name := fields[0]
|
||||
version := fields[1]
|
||||
|
||||
p := pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Locations: file.NewLocationSet(l.Location),
|
||||
Type: pkg.NpmPkg,
|
||||
PURL: packageurl.NewPackageURL(
|
||||
packageurl.TypeNPM,
|
||||
"",
|
||||
name,
|
||||
version,
|
||||
nil,
|
||||
"",
|
||||
).ToString(),
|
||||
Language: pkg.JavaScript,
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
pkgs = append(pkgs, p)
|
||||
}
|
||||
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func newLibmanJSON(reader file.LocationReadCloser) (*libmanJSON, error) {
|
||||
var doc libmanJSON
|
||||
dec := json.NewDecoder(reader)
|
||||
if err := dec.Decode(&doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range doc.Libraries {
|
||||
l := &doc.Libraries[i]
|
||||
if l.Provider == "" {
|
||||
l.Provider = doc.DefaultProvider
|
||||
}
|
||||
}
|
||||
|
||||
doc.Location = reader.Location
|
||||
|
||||
return &doc, nil
|
||||
}
|
||||
|
||||
func findLibmanJSON(resolver file.Resolver, depsJSON file.Location) (*libmanJSON, error) {
|
||||
parent := path.Dir(depsJSON.RealPath)
|
||||
loc := resolver.RelativeFileByPath(depsJSON, path.Join(parent, "libman.json"))
|
||||
if loc == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
reader, err := resolver.FileContentsByLocation(*loc)
|
||||
defer internal.CloseAndLogError(reader, loc.RealPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
internal.CloseAndLogError(reader, loc.RealPath)
|
||||
|
||||
lj, err := newLibmanJSON(file.NewLocationReadCloser(*loc, reader))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return lj, nil
|
||||
}
|
||||
@@ -196,9 +196,8 @@ func extractNameAndVersion(nameVersion string) (name, version string) {
|
||||
return
|
||||
}
|
||||
|
||||
func createNameAndVersion(name, version string) (nameVersion string) {
|
||||
nameVersion = fmt.Sprintf("%s/%s", name, version)
|
||||
return
|
||||
func createNameAndVersion(name, version string) string {
|
||||
return fmt.Sprintf("%s/%s", name, version)
|
||||
}
|
||||
|
||||
func packageURL(m pkg.DotnetDepsEntry) string {
|
||||
|
||||
@@ -69,7 +69,7 @@ func parseDotnetPackagesLock(_ context.Context, _ file.Resolver, _ *generic.Envi
|
||||
name, _ := extractNameAndVersion(nameVersion)
|
||||
|
||||
dep := allDependencies[nameVersion]
|
||||
dotnetPkg := newDotnetPackagesLockPackage(name, dep, reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
|
||||
dotnetPkg := newDotnetPackagesLockPackage(name, dep, reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
|
||||
if dotnetPkg != nil {
|
||||
pkgs = append(pkgs, *dotnetPkg)
|
||||
pkgMap[nameVersion] = *dotnetPkg
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
.gitignore
|
||||
Dockerfile
|
||||
@@ -0,0 +1,2 @@
|
||||
/app
|
||||
/extract.sh
|
||||
@@ -0,0 +1,13 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
ARG RUNTIME=win-x64
|
||||
|
||||
COPY . .
|
||||
WORKDIR /src
|
||||
RUN dotnet restore -r $RUNTIME
|
||||
RUN dotnet publish -c Release --no-restore -o /app
|
||||
|
||||
FROM busybox:latest
|
||||
WORKDIR /app
|
||||
COPY --from=build /app .
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
wwwroot/lib/
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- A PackageReference to Microsoft.AspNetCore.App is not necessary when targeting .NET Core 3.0 or higher. If Microsoft.NET.Sdk.Web is used, the shared framework will be referenced automatically (or override with FrameworkReference) -->
|
||||
<!-- <PackageReference Include="Microsoft.AspNetCore.App" /> -->
|
||||
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LibManSample
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LibManSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.Run(async (context) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Hello World!");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"defaultProvider": "cdnjs",
|
||||
"libraries": [
|
||||
{
|
||||
"library": "jquery@3.3.1",
|
||||
"files": [
|
||||
"jquery.min.js",
|
||||
"jquery.js",
|
||||
"jquery.min.map"
|
||||
],
|
||||
"destination": "wwwroot/lib/jquery/"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "vendor",
|
||||
"files": [
|
||||
"lodash.js",
|
||||
"lodash.min.js"
|
||||
],
|
||||
"destination": "wwwroot/lib/lodash/"
|
||||
}
|
||||
]
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
// jk! nothing to see here!
|
||||
+1
@@ -0,0 +1 @@
|
||||
// still nothing here...
|
||||
@@ -0,0 +1,2 @@
|
||||
/app
|
||||
/extract.sh
|
||||
@@ -0,0 +1,17 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine@sha256:3f93439f47fea888d94e6e228d0d0de841f4122ef46f8bfd04f8bd78cbce7ddb AS build
|
||||
ARG RUNTIME=win-x64
|
||||
WORKDIR /src
|
||||
|
||||
COPY src/helloworld.csproj .
|
||||
RUN dotnet restore -r $RUNTIME
|
||||
|
||||
COPY src/*.cs .
|
||||
RUN dotnet publish -c Release -r $RUNTIME --self-contained false -o /app
|
||||
|
||||
# note: we're not using a runtime here to make testing easier... so you cannot run this container and expect it to work
|
||||
# we do this to keep the test assertions small since the don't want to include the several other runtime packages
|
||||
FROM busybox:latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=build /app .
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace HelloWorld
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var app = builder.Build();
|
||||
|
||||
// configure the HTTP request pipeline
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
}
|
||||
|
||||
// enable serving static files (including jQuery)
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.MapGet("/", () => "Hello World!");
|
||||
|
||||
Console.WriteLine("Application starting...");
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetNuke.Core" Version="9.9.1"/>
|
||||
|
||||
<!-- jQuery wraps the javascript library, so no DLLs -->
|
||||
<PackageReference Include="jQuery" Version="3.4.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
|
||||
|
||||
<!-- ChakraCore is an open source Javascript engine with a C API -->
|
||||
<PackageReference Include="Microsoft.ChakraCore" Version="1.11.24">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
<!-- Nuget.CommandLine is a command line tool for managing NuGet packages -->
|
||||
<PackageReference Include="Nuget.CommandLine" Version="6.3.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
<!-- Umbraco.Cms has dependencies with software, but itself has no DLLs -->
|
||||
<PackageReference Include="Umbraco.Cms" Version="11.3.0" />
|
||||
|
||||
<!-- For code analysis/style checking, only needed during development -->
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
|
||||
|
||||
<!-- For unit testing, only needed during development -->
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" Condition="'$(Configuration)' == 'Debug'" PrivateAssets="All" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<!-- create directories if they don't exist -->
|
||||
<Target Name="CreateWwwroot" BeforeTargets="PrepareForPublish">
|
||||
<MakeDir Directories="$(PublishDir)wwwroot\lib\jquery" />
|
||||
</Target>
|
||||
|
||||
<!-- explicitly copy jQuery files during publish phase -->
|
||||
<Target Name="CopyJQueryToPublishOutput" AfterTargets="CreateWwwroot" BeforeTargets="ComputeFilesToPublish">
|
||||
<ItemGroup>
|
||||
<!-- find jQuery files in the packages folder -->
|
||||
<JQueryFiles Include="$(NuGetPackageRoot)\jquery\3.4.1\Content\Scripts\*.js" />
|
||||
|
||||
<!-- add these to the publish output -->
|
||||
<ResolvedFileToPublish Include="@(JQueryFiles)">
|
||||
<RelativePath>wwwroot\lib\jquery\%(Filename)%(Extension)</RelativePath>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</ResolvedFileToPublish>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
@@ -61,7 +61,7 @@ func parseMixLock(_ context.Context, _ file.Resolver, _ *generic.Environment, re
|
||||
PkgHash: hash,
|
||||
PkgHashExt: hashExt,
|
||||
},
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func parseOTPApp(_ context.Context, _ file.Resolver, _ *generic.Environment, rea
|
||||
|
||||
p := newPackageFromOTP(
|
||||
name, version,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
packages = append(packages, p)
|
||||
|
||||
@@ -56,7 +56,7 @@ func parseRebarLock(_ context.Context, _ file.Resolver, _ *generic.Environment,
|
||||
Name: name,
|
||||
Version: version,
|
||||
},
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
pkgMap[name] = &p
|
||||
|
||||
@@ -27,14 +27,14 @@ var (
|
||||
|
||||
// parses individual CONTENTS files from the portage flat-file store (e.g. /var/db/pkg/*/*/CONTENTS).
|
||||
func parsePortageContents(_ context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
cpvMatch := cpvRe.FindStringSubmatch(reader.Location.RealPath)
|
||||
cpvMatch := cpvRe.FindStringSubmatch(reader.RealPath)
|
||||
if cpvMatch == nil {
|
||||
return nil, nil, fmt.Errorf("failed to match package and version in %s", reader.Location.RealPath)
|
||||
return nil, nil, fmt.Errorf("failed to match package and version in %s", reader.RealPath)
|
||||
}
|
||||
|
||||
name, version := cpvMatch[1], cpvMatch[2]
|
||||
if name == "" || version == "" {
|
||||
log.WithFields("path", reader.Location.RealPath).Debug("failed to parse portage name and version")
|
||||
log.WithFields("path", reader.RealPath).Debug("failed to parse portage name and version")
|
||||
return nil, nil, fmt.Errorf("failed to parse portage name and version")
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func parsePortageContents(_ context.Context, resolver file.Resolver, _ *generic.
|
||||
Version: version,
|
||||
PURL: packageURL(name, version),
|
||||
Locations: file.NewLocationSet(
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
Type: pkg.PortagePkg,
|
||||
Metadata: pkg.PortageEntry{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user