Compare commits

...
14 Commits
Author SHA1 Message Date
Christopher Angelo PhillipsandKeith Zantow 8a41d77250 chore: prevent file resolver from bubbling errors in binary cataloger (#3410)
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2024-11-04 20:23:27 +00:00
anchore-actions-token-generator[bot]andkzantow eb56f2e4bb chore(deps): update stereoscope to cbd43fb4e5d348fe680066ee6329385fd6a4f827 (#3411)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kzantow <3009477+kzantow@users.noreply.github.com>
2024-11-04 10:20:27 -05:00
anchore-actions-token-generator[bot]andwagoodman 849e325408 chore(deps): update CPE dictionary index (#3414)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: wagoodman <590471+wagoodman@users.noreply.github.com>
2024-11-04 10:13:22 -05:00
dependabot[bot] 203df65a65 chore(deps): bump github.com/adrg/xdg from 0.5.2 to 0.5.3 (#3408)
Bumps [github.com/adrg/xdg](https://github.com/adrg/xdg) from 0.5.2 to 0.5.3.
- [Release notes](https://github.com/adrg/xdg/releases)
- [Commits](https://github.com/adrg/xdg/compare/v0.5.2...v0.5.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-01 11:43:54 -04:00
dependabot[bot] 2c70090d10 chore(deps): bump github.com/charmbracelet/lipgloss from 0.13.1 to 1.0.0 (#3409)
Bumps [github.com/charmbracelet/lipgloss](https://github.com/charmbracelet/lipgloss) from 0.13.1 to 1.0.0.
- [Release notes](https://github.com/charmbracelet/lipgloss/releases)
- [Changelog](https://github.com/charmbracelet/lipgloss/blob/master/.goreleaser.yml)
- [Commits](https://github.com/charmbracelet/lipgloss/compare/v0.13.1...v1.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-01 11:43:47 -04:00
anchore-actions-token-generator[bot]andkzantow 8f179e6961 chore(deps): update stereoscope to 2ce1e520983b1c21d5150d7fae2b39e8e5ab9063 (#3405)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kzantow <3009477+kzantow@users.noreply.github.com>
2024-11-01 11:43:39 -04:00
Artemii 6a1e3f32fe Issue #3143 – fixed format conversion docs link (#3407)
* chore: fixed format conversion docs link (#3143)

Signed-off-by: Artemii Fedotov <artemii.fedotov@tutamail.com>

* changed link to wiki docs

Signed-off-by: Artemii Fedotov <artemii.fedotov@tutamail.com>

---------

Signed-off-by: Artemii Fedotov <artemii.fedotov@tutamail.com>
2024-11-01 11:43:00 -04:00
Joel Rudsberg fcf1350a0e feat: support dependencies and purl for Native Image SBOMs (#3399)
Signed-off-by: Joel Rudsberg <joel.rudsberg@oracle.com>
2024-10-31 12:12:54 -04:00
anchore-actions-token-generator[bot]andkzantow 9302e20d62 chore(deps): update stereoscope to 9c92fe30492ffeba14ed2e23ad1fd923341dda4f (#3398)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kzantow <3009477+kzantow@users.noreply.github.com>
2024-10-31 10:22:14 -04:00
Nathan VossandKeith Zantow a55b71d4ef feat: exclude devDependencies from package-lock.json parsing (#3371)
Signed-off-by: Nathan Voss <njvoss299@gmail.com>
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2024-10-30 12:02:27 -04:00
dependabot[bot] df3998b4f1 chore(deps): bump github.com/adrg/xdg from 0.5.1 to 0.5.2 (#3394) 2024-10-29 16:32:14 +00:00
dependabot[bot] 9dc9be645a chore(deps): bump anchore/sbom-action from 0.17.5 to 0.17.6 (#3393)
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.17.5 to 0.17.6.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/1ca97d9028b51809cf6d3c934c3e160716e1b605...251a468eed47e5082b105c3ba6ee500c0e65a764)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-29 10:07:28 -04:00
Keith Zantow 798c18a698 fix: stack overflow in spyingIoReadCloser (#3392)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-10-29 08:23:57 -04:00
Keith Zantow 1118ac4ace fix: bad pom files may cause infinite loop (#3391)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2024-10-28 18:09:04 -04:00
29 changed files with 614 additions and 201 deletions
+1 -1
View File
@@ -148,7 +148,7 @@ jobs:
# for updating brew formula in anchore/homebrew-syft
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
- uses: anchore/sbom-action@1ca97d9028b51809cf6d3c934c3e160716e1b605 #v0.17.5
- uses: anchore/sbom-action@251a468eed47e5082b105c3ba6ee500c0e65a764 #v0.17.6
continue-on-error: true
with:
artifact-name: sbom.spdx.json
+2 -2
View File
@@ -17,7 +17,7 @@ import (
const (
convertExample = ` {{.appName}} {{.command}} img.syft.json -o spdx-json convert a syft SBOM to spdx-json, output goes to stdout
{{.appName}} {{.command}} img.syft.json -o cyclonedx-json=img.cdx.json convert a syft SBOM to CycloneDX, output is written to the file "img.cdx.json""
{{.appName}} {{.command}} img.syft.json -o cyclonedx-json=img.cdx.json convert a syft SBOM to CycloneDX, output is written to the file "img.cdx.json"
{{.appName}} {{.command}} - -o spdx-json convert an SBOM from STDIN to spdx-json
`
)
@@ -39,7 +39,7 @@ func Convert(app clio.Application) *cobra.Command {
return app.SetupCommand(&cobra.Command{
Use: "convert [SOURCE-SBOM] -o [FORMAT]",
Short: "Convert between SBOM formats",
Long: "[Experimental] Convert SBOM files to, and from, SPDX, CycloneDX and Syft's format. For more info about data loss between formats see https://github.com/anchore/syft#format-conversion-experimental",
Long: "[Experimental] Convert SBOM files to, and from, SPDX, CycloneDX and Syft's format. For more info about data loss between formats see https://github.com/anchore/syft/wiki/format-conversion",
Example: internal.Tprintf(convertExample, map[string]interface{}{
"appName": id.Name,
"command": "convert",
+1
View File
@@ -166,6 +166,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config {
WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags),
),
JavaScript: javascript.DefaultCatalogerConfig().
WithIncludeDevDependencies(*multiLevelOption(false, cfg.JavaScript.IncludeDevDependencies)).
WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.JavaScript, task.Node, task.NPM), cfg.JavaScript.SearchRemoteLicenses)).
WithNpmBaseURL(cfg.JavaScript.NpmBaseURL),
LinuxKernel: kernel.LinuxKernelCatalogerConfig{
+4 -2
View File
@@ -3,8 +3,9 @@ package options
import "github.com/anchore/clio"
type javaScriptConfig struct {
SearchRemoteLicenses *bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
NpmBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
SearchRemoteLicenses *bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
NpmBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
IncludeDevDependencies *bool `json:"include-dev-dependencies" yaml:"include-dev-dependencies" mapstructure:"include-dev-dependencies"`
}
var _ interface {
@@ -14,4 +15,5 @@ var _ interface {
func (o *javaScriptConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
descriptions.Add(&o.SearchRemoteLicenses, `enables Syft to use the network to fill in more detailed license information`)
descriptions.Add(&o.NpmBaseURL, `base NPM url to use`)
descriptions.Add(&o.IncludeDevDependencies, `include development-scoped dependencies`)
}
@@ -25,7 +25,7 @@ func TestNpmPackageLockDirectory(t *testing.T) {
}
// ensure that integration test commonTestCases stay in sync with the available catalogers
const expectedPackageCount = 6
const expectedPackageCount = 2
if foundPackages.Size() != expectedPackageCount {
t.Errorf("found the wrong set of npm package-lock.json packages (expected: %d, actual: %d)", expectedPackageCount, foundPackages.Size())
}
+4 -4
View File
@@ -17,7 +17,7 @@ require (
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f
github.com/anchore/stereoscope v0.0.5
github.com/anchore/stereoscope v0.0.6-0.20241101185849-cbd43fb4e5d3
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
// we are hinting brotli to latest due to warning when installing archiver v3:
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
@@ -25,7 +25,7 @@ require (
github.com/bmatcuk/doublestar/v4 v4.7.1
github.com/charmbracelet/bubbles v0.20.0
github.com/charmbracelet/bubbletea v1.1.2
github.com/charmbracelet/lipgloss v0.13.1
github.com/charmbracelet/lipgloss v1.0.0
github.com/dave/jennifer v1.7.1
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
github.com/distribution/reference v0.6.0
@@ -89,7 +89,7 @@ require google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirec
require (
github.com/BurntSushi/toml v1.4.0
github.com/OneOfOne/xxhash v1.2.8
github.com/adrg/xdg v0.5.1
github.com/adrg/xdg v0.5.3
github.com/magiconair/properties v1.8.7
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
)
@@ -111,7 +111,7 @@ require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/charmbracelet/harmonica v0.2.0 // indirect
github.com/charmbracelet/x/ansi v0.4.0 // indirect
github.com/charmbracelet/x/ansi v0.4.2 // indirect
github.com/charmbracelet/x/term v0.2.0 // indirect
github.com/cloudflare/circl v1.3.8 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
+8 -8
View File
@@ -87,8 +87,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY=
github.com/adrg/xdg v0.5.1 h1:Im8iDbEFARltY09yOJlSGu4Asjk2vF85+3Dyru8uJ0U=
github.com/adrg/xdg v0.5.1/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -115,8 +115,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.20241018175412-5c22e6360c4f h1:dAQPIrQ3a5PBqZeZ+B9NGZsGmodk4NO9OjDIsQmQyQM=
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI=
github.com/anchore/stereoscope v0.0.5 h1:PILlvsQS3+dT5rNsDudRhi91jukR65y2itG1lQOLn0s=
github.com/anchore/stereoscope v0.0.5/go.mod h1:jwK34VB049/iRE1DyWUv4ZWraOaFQ+FpurgvkWMGQzQ=
github.com/anchore/stereoscope v0.0.6-0.20241101185849-cbd43fb4e5d3 h1:T1LMkKwzSg1s8+xylq51xroPoo83Nt3zQPvdRRDB9Bw=
github.com/anchore/stereoscope v0.0.6-0.20241101185849-cbd43fb4e5d3/go.mod h1:jgLIzIwEkfMhjhKmuzaSEeU2/vFCqlO3XTrSeSLfOaM=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
@@ -163,10 +163,10 @@ github.com/charmbracelet/bubbletea v1.1.2 h1:naQXF2laRxyLyil/i7fxdpiz1/k06IKquhm
github.com/charmbracelet/bubbletea v1.1.2/go.mod h1:9HIU/hBV24qKjlehyj8z1r/tR9TYTQEag+cWZnuXo8E=
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.13.1 h1:Oik/oqDTMVA01GetT4JdEC033dNzWoQHdWnHnQmXE2A=
github.com/charmbracelet/lipgloss v0.13.1/go.mod h1:zaYVJ2xKSKEnTEEbX6uAHabh2d975RJ+0yfkFpRBz5U=
github.com/charmbracelet/x/ansi v0.4.0 h1:NqwHA4B23VwsDn4H3VcNX1W1tOmgnvY1NDx5tOXdnOU=
github.com/charmbracelet/x/ansi v0.4.0/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
github.com/charmbracelet/x/ansi v0.4.2 h1:0JM6Aj/g/KC154/gOP4vfxun0ff6itogDYk41kof+qk=
github.com/charmbracelet/x/ansi v0.4.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+12 -5
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"runtime/debug"
"slices"
"sync"
"time"
@@ -57,14 +58,14 @@ func (p *Executor) Execute(ctx context.Context, resolver file.Resolver, s sbomsy
}
err := runTaskSafely(ctx, tsk, resolver, s)
unknowns, err := unknown.ExtractCoordinateErrors(err)
unknowns, remainingErrors := unknown.ExtractCoordinateErrors(err)
if len(unknowns) > 0 {
appendUnknowns(s, tsk.Name(), unknowns)
}
if err != nil {
if remainingErrors != nil {
withLock(func() {
errs = multierror.Append(errs, fmt.Errorf("failed to run task: %w", err))
prog.SetError(err)
errs = multierror.Append(errs, fmt.Errorf("failed to run task: %w", remainingErrors))
prog.SetError(remainingErrors)
})
}
prog.Increment()
@@ -84,7 +85,13 @@ func appendUnknowns(builder sbomsync.Builder, taskName string, unknowns []unknow
if sb.Artifacts.Unknowns == nil {
sb.Artifacts.Unknowns = map[file.Coordinates][]string{}
}
sb.Artifacts.Unknowns[u.Coordinates] = append(sb.Artifacts.Unknowns[u.Coordinates], formatUnknown(u.Reason.Error(), taskName))
unknownText := formatUnknown(u.Reason.Error(), taskName)
existing := sb.Artifacts.Unknowns[u.Coordinates]
// don't include duplicate unknowns
if slices.Contains(existing, unknownText) {
continue
}
sb.Artifacts.Unknowns[u.Coordinates] = append(existing, unknownText)
}
})
}
+33
View File
@@ -0,0 +1,33 @@
package unknown
import (
"regexp"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/file"
)
var pathErrorRegex = regexp.MustCompile(`.*path="([^"]+)".*`)
// ProcessPathErrors replaces "path" errors returned from the file.Resolver into unknowns,
// and warn logs non-unknown errors, returning only the unknown errors
func ProcessPathErrors(err error) error {
if err == nil {
return nil
}
errText := err.Error()
if pathErrorRegex.MatchString(errText) {
foundPath := pathErrorRegex.ReplaceAllString(err.Error(), "$1")
if foundPath != "" {
return New(file.NewLocation(foundPath), err)
}
}
unknowns, remainingErrors := ExtractCoordinateErrors(err)
log.Warn(remainingErrors)
var out []error
for _, u := range unknowns {
out = append(out, &u)
}
return Join(out...)
}
+56
View File
@@ -0,0 +1,56 @@
package unknown
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/file"
)
func Test_ProcessPathErrors(t *testing.T) {
tests := []struct {
errorText string
expected error
}{
{
errorText: `prefix path="/var/lib/thing" suffix`,
expected: &CoordinateError{
Coordinates: file.Coordinates{
RealPath: "/var/lib/thing",
},
Reason: fmt.Errorf(`prefix path="/var/lib/thing" suffix`),
},
},
{
errorText: `prefix path="/var/lib/thing"`,
expected: &CoordinateError{
Coordinates: file.Coordinates{
RealPath: "/var/lib/thing",
},
Reason: fmt.Errorf(`prefix path="/var/lib/thing"`),
},
},
{
errorText: `path="/var/lib/thing" suffix`,
expected: &CoordinateError{
Coordinates: file.Coordinates{
RealPath: "/var/lib/thing",
},
Reason: fmt.Errorf(`path="/var/lib/thing" suffix`),
},
},
{
errorText: "all your base are belong to us",
expected: nil,
},
}
for _, test := range tests {
t.Run(test.errorText, func(t *testing.T) {
got := ProcessPathErrors(fmt.Errorf("%s", test.errorText))
require.Equal(t, test.expected, got)
})
}
}
@@ -105,6 +105,7 @@ func catalog(resolver file.Resolver, cls Classifier) (packages []pkg.Package, er
var errs error
locations, err := resolver.FilesByGlob(cls.FileGlob)
if err != nil {
err = unknown.ProcessPathErrors(err) // convert any file.Resolver path errors to unknowns with locations
return nil, err
}
for _, location := range locations {
@@ -1668,7 +1668,7 @@ func Test_Cataloger_ResilientToErrors(t *testing.T) {
resolver := &panicyResolver{}
_, _, err := c.Catalog(context.Background(), resolver)
assert.Error(t, err)
assert.Nil(t, err) // non-coordinate-based FindBy* errors are now logged and not returned
assert.True(t, resolver.searchCalled)
}
+1 -1
View File
@@ -108,7 +108,7 @@ func newSpyReturningFileResolver(s *spyingIoReadCloser, paths ...string) file.Re
}
func (s *spyingIoReadCloser) Read(p []byte) (n int, err error) {
return s.Read(p)
return s.rc.Read(p)
}
func (s *spyingIoReadCloser) Close() error {
@@ -7544,7 +7544,7 @@
"cpe:2.3:a:plugins360:all-in-one_video_gallery:*:*:*:*:*:wordpress:*:*"
],
"all-in-one-wp-migration": [
"cpe:2.3:a:servmask:all-in-one_wp_migration:*:*:*:*:*:wordpress:*:*"
"cpe:2.3:a:servmask:all-in-one_wp_migration:*:*:*:*:free:wordpress:*:*"
],
"all-in-one-wp-security-and-firewall": [
"cpe:2.3:a:tips_and_tricks_hq:all_in_one_wordpress_security_and_firewall:*:*:*:*:*:wordpress:*:*",
@@ -7649,6 +7649,9 @@
"analytics-tracker": [
"cpe:2.3:a:analytics_tracker_project:analytics_tracker:*:*:*:*:*:wordpress:*:*"
],
"anchor-episodes-index": [
"cpe:2.3:a:jesweb:anchor_episodes_index:*:*:*:*:*:wordpress:*:*"
],
"animate-it": [
"cpe:2.3:a:eleopard:animate_it\\!:*:*:*:*:*:wordpress:*:*"
],
@@ -8054,6 +8057,9 @@
"bdthemes-element-pack-lite#tags": [
"cpe:2.3:a:bdthemes:element_pack:*:*:*:*:lite:wordpress:*:*"
],
"bdthemes-prime-slider-lite": [
"cpe:2.3:a:bdthemes:prime_slider:*:*:*:*:free:wordpress:*:*"
],
"bdvs-password-reset": [
"cpe:2.3:a:bedevious:password_reset_with_code_for_wordpress_rest_api:*:*:*:*:*:wordpress:*:*"
],
@@ -8768,6 +8774,9 @@
"clerkio": [
"cpe:2.3:a:clerk:clerk.io:*:*:*:*:*:wordpress:*:*"
],
"clever-fox": [
"cpe:2.3:a:nayrathemes:clever_fox:*:*:*:*:*:wordpress:*:*"
],
"click-datos-lopd": [
"cpe:2.3:a:clickdatos:proteccion_de_datos_rgpd:*:*:*:*:*:wordpress:*:*"
],
@@ -9263,6 +9272,9 @@
"cpe:2.3:a:codeless:cowidgets_-_elementor:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:codeless:cowidgets_elementor_addons:*:*:*:*:*:wordpress:*:*"
],
"cozy-addons": [
"cpe:2.3:a:cozythemes:cozy_blocks:*:*:*:*:*:wordpress:*:*"
],
"cp-appointment-calendar": [
"cpe:2.3:a:codepeople:cp_appointment_calendar:*:*:*:*:*:wordpress:*:*"
],
@@ -10286,7 +10298,8 @@
"cpe:2.3:a:eshop_project:eshop:*:*:*:*:*:wordpress:*:*"
],
"essential-addons-for-elementor-lite": [
"cpe:2.3:a:wpdeveloper:essential_addons_for_elementor:*:*:*:*:*:wordpress:*:*"
"cpe:2.3:a:wpdeveloper:essential_addons_for_elementor:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:wpdeveloper:essential_addons_for_elementor:*:*:*:*:lite:wordpress:*:*"
],
"essential-blocks": [
"cpe:2.3:a:wpdeveloper:essential_blocks:*:*:*:*:*:wordpress:*:*",
@@ -12088,6 +12101,9 @@
"kangu": [
"cpe:2.3:a:kangu:kangu:*:*:*:*:*:wordpress:*:*"
],
"kata-plus": [
"cpe:2.3:a:climaxthemes:kata_plus:*:*:*:*:*:wordpress:*:*"
],
"kau-boys-backend-localization": [
"cpe:2.3:a:kau-boys:backend_localization:*:*:*:*:*:wordpress:*:*"
],
@@ -12610,6 +12626,9 @@
"martins-link-network": [
"cpe:2.3:a:martinstools:free_\\\u0026_easy_link_building:*:*:*:*:*:wordpress:*:*"
],
"mas-addons-for-elementor": [
"cpe:2.3:a:madrasthemes:mas_elementor:*:*:*:*:*:wordpress:*:*"
],
"mas-static-content": [
"cpe:2.3:a:madrasthemes:mas_static_content:*:*:*:*:*:wordpress:*:*"
],
@@ -12716,12 +12735,18 @@
"meks-audio-player": [
"cpe:2.3:a:mekshq:meks_audio_player:*:*:*:*:*:wordpress:*:*"
],
"meks-easy-ads-widget": [
"cpe:2.3:a:mekshq:meks_easy_ads_widget:*:*:*:*:*:wordpress:*:*"
],
"meks-easy-instagram-widget": [
"cpe:2.3:a:mekshq:meks_easy_photo_feed_widget:*:*:*:*:*:wordpress:*:*"
],
"meks-flexible-shortcodes": [
"cpe:2.3:a:mekshq:meks_flexible_shortcodes:*:*:*:*:*:wordpress:*:*"
],
"meks-smart-author-widget": [
"cpe:2.3:a:mekshq:meks_smart_author_widget:*:*:*:*:*:wordpress:*:*"
],
"meks-smart-social-widget": [
"cpe:2.3:a:mekshq:meks_smart_social_widget:*:*:*:*:*:wordpress:*:*"
],
@@ -12858,6 +12883,9 @@
"mobile-login-woocommerce": [
"cpe:2.3:a:xootix:otp_login_woocommerce_\\\u0026_gravity_forms:*:*:*:*:*:wordpress:*:*"
],
"mobile-menu": [
"cpe:2.3:a:freshlightlab:wp_mobile_menu:*:*:*:*:*:wordpress:*:*"
],
"modal-dialog": [
"cpe:2.3:a:modal_dialog_project:modal_dialog:*:*:*:*:*:wordpress:*:*"
],
@@ -13226,6 +13254,9 @@
"cpe:2.3:a:ninjaforms:contact_form:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:ninjaforms:ninja_forms:*:*:*:*:*:wordpress:*:*"
],
"ninja-gdpr-compliance": [
"cpe:2.3:a:ninjateam:gdpr_ccpa_compliance_\\\u0026_cookie_consent_banner:*:*:*:*:*:wordpress:*:*"
],
"ninja-job-board": [
"cpe:2.3:a:wpmanageninja:ninja_job_board:*:*:*:*:*:wordpress:*:*"
],
@@ -14165,6 +14196,9 @@
"profilegrid-user-profiles-groups-and-communities": [
"cpe:2.3:a:metagauss:profilegrid:*:*:*:*:*:wordpress:*:*"
],
"profilepress-pro": [
"cpe:2.3:a:properfraction:profilepress:*:*:*:*:pro:wordpress:*:*"
],
"profit-products-tables-for-woocommerce": [
"cpe:2.3:a:pluginus:woot:*:*:*:*:*:wordpress:*:*"
],
@@ -15051,7 +15085,8 @@
"cpe:2.3:a:bainternet:shortcodes_ui:*:*:*:*:*:wordpress:*:*"
],
"shortcodes-ultimate": [
"cpe:2.3:a:getshortcodes:shortcodes_ultimate:*:*:*:*:*:wordpress:*:*"
"cpe:2.3:a:getshortcodes:shortcodes_ultimate:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:getshortcodes:shortcodes_ultimate:*:*:*:*:-:wordpress:*:*"
],
"shortcut-macros": [
"cpe:2.3:a:shortcut_macros_project:shortcut_macros:*:*:*:*:*:wordpress:*:*"
@@ -15846,7 +15881,7 @@
"cpe:2.3:a:instawp:string_locator:*:*:*:*:*:wordpress:*:*"
],
"strong-testimonials": [
"cpe:2.3:a:machothemes:strong_testimonials:*:*:*:*:*:wordpress:*:*"
"cpe:2.3:a:wpchill:strong_testimonials:*:*:*:*:*:wordpress:*:*"
],
"structured-content": [
"cpe:2.3:a:wpsc-plugin:structured_content:*:*:*:*:*:wordpress:*:*"
@@ -16290,6 +16325,9 @@
"transbank-webpay-plus-rest": [
"cpe:2.3:a:transbank:transbank_webpay_rest:*:*:*:*:*:wordpress:*:*"
],
"transients-manager": [
"cpe:2.3:a:wpbeginner:transients_manager:*:*:*:*:*:wordpress:*:*"
],
"transition-slider-lite": [
"cpe:2.3:a:creativeinteractivemedia:transition_slider:*:*:*:*:*:wordpress:*:*"
],
@@ -16796,6 +16834,9 @@
"vm-backups": [
"cpe:2.3:a:vm_backups_project:vm_backups:*:*:*:*:*:wordpress:*:*"
],
"vod-infomaniak": [
"cpe:2.3:a:infomaniak:vod_infomaniak:*:*:*:*:*:wordpress:*:*"
],
"vospari-forms": [
"cpe:2.3:a:vospari_forms_project:vospari_forms:*:*:*:*:*:wordpress:*:*"
],
@@ -17255,6 +17296,9 @@
"woo-zoho": [
"cpe:2.3:a:crmperks:integration_for_woocommerce_and_zoho_crm\\,_books\\,_invoice\\,_inventory\\,_bigin:*:*:*:*:*:*:*:*"
],
"wooCommerce-order-proposal": [
"cpe:2.3:a:wpovernight:woocommerce_order_proposal:*:*:*:*:*:wordpress:*:*"
],
"woocommerce": [
"cpe:2.3:a:woocommerce:woocommerce:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:woocommerce:woocommerce:*:*:*:*:free:wordpress:*:*",
@@ -17891,6 +17935,9 @@
"wp-football": [
"cpe:2.3:a:wp-football_project:wp-football:*:*:*:*:*:*:*:*"
],
"wp-force-ssl": [
"cpe:2.3:a:webfactoryltd:wp_force_ssl:*:*:*:*:free:wordpress:*:*"
],
"wp-forms-puzzle-captcha": [
"cpe:2.3:a:nitinrathod:wp_forms_puzzle_captcha:*:*:*:*:*:wordpress:*:*"
],
@@ -18043,6 +18090,9 @@
"wp-jobs": [
"cpe:2.3:a:intensewp:wp_jobs:*:*:*:*:*:wordpress:*:*"
],
"wp-jquery-lightbox": [
"cpe:2.3:a:lightpress:lightbox:*:*:*:*:*:wordpress:*:*"
],
"wp-js": [
"cpe:2.3:a:wp-js_project:wp-js:*:*:*:*:*:wordpress:*:*"
],
@@ -18150,7 +18200,7 @@
"cpe:2.3:a:jeffrey-wp:media_library_categories:*:*:*:*:*:wordpress:*:*"
],
"wp-members": [
"cpe:2.3:a:wp-members_project:wp-members:*:*:*:*:*:wordpress:*:*"
"cpe:2.3:a:butlerblog:wp-members:*:*:*:*:*:wordpress:*:*"
],
"wp-memory": [
"cpe:2.3:a:wp-memory_project:wp-memory:*:*:*:*:*:wordpress:*:*"
@@ -18641,7 +18691,8 @@
"wp-user-avatar": [
"cpe:2.3:a:profilepress:profilepress:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:profilepress:user_registration\\,_login_form\\,_user_profile_\\\u0026_membership:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:properfraction:profilepress:*:*:*:*:*:wordpress:*:*"
"cpe:2.3:a:properfraction:profilepress:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:properfraction:profilepress:*:*:*:*:free:wordpress:*:*"
],
"wp-user-frontend": [
"cpe:2.3:a:wedevs:wp_user_frontend:*:*:*:*:*:wordpress:*:*"
@@ -18738,6 +18789,9 @@
"wpbulky-wp-bulk-edit-post-types": [
"cpe:2.3:a:villatheme:wpbulky:*:*:*:*:*:wordpress:*:*"
],
"wpc-shop-as-customer": [
"cpe:2.3:a:wpclever:wpc_shop_as_a_customer_for_woocommerce:*:*:*:*:*:wordpress:*:*"
],
"wpcalc": [
"cpe:2.3:a:wow-company:wpcalc:*:*:*:*:*:wordpress:*:*"
],
@@ -18901,7 +18955,7 @@
"cpe:2.3:a:wpvivid:migration\\,_backup\\,_staging:*:*:*:*:*:wordpress:*:*"
],
"wpvr": [
"cpe:2.3:a:coderex:wp_vr:*:*:*:*:*:wordpress:*:*"
"cpe:2.3:a:rextheme:wp_vr:*:*:*:*:*:wordpress:*:*"
],
"wpzoom-elementor-addons": [
"cpe:2.3:a:wpzoom:wpzoom_elementor_addons:*:*:*:*:*:wordpress:*:*"
@@ -19016,6 +19070,10 @@
"cpe:2.3:a:codeparrots:easy_forms_for_mailchimp:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:yikesinc:easy_forms_for_mailchimp:*:*:*:*:*:wordpress:*:*"
],
"yith-custom-login": [
"cpe:2.3:a:yithemes:yith_custom_login:*:*:*:*:*:wordpress:*:*",
"cpe:2.3:a:yithemes:yith_custom_login:*:*:*:*:wordpress:*:*:*"
],
"yith-desktop-notifications-for-woocommerce": [
"cpe:2.3:a:yithemes:yith_desktop_notifications_for_woocommerce:*:*:*:*:*:wordpress:*:*"
],
@@ -19298,6 +19356,9 @@
"fluida": [
"cpe:2.3:a:cryoutcreations:fluida:*:*:*:*:*:wordpress:*:*"
],
"formula": [
"cpe:2.3:a:awplife:formula:*:*:*:*:free:wordpress:*:*"
],
"fullbase": [
"cpe:2.3:a:marchettidesign:fullbase:*:*:*:*:*:wordpress:*:*"
],
@@ -8,7 +8,6 @@ import (
"debug/macho"
"debug/pe"
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
@@ -18,34 +17,14 @@ import (
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/mimetype"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/format/cyclonedxjson"
"github.com/anchore/syft/syft/internal/unionreader"
"github.com/anchore/syft/syft/pkg"
)
type nativeImageCycloneDX struct {
BomFormat string `json:"bomFormat"`
SpecVersion string `json:"specVersion"`
Version int `json:"version"`
Components []nativeImageComponent `json:"components"`
}
type nativeImageComponent struct {
Type string `json:"type"`
Group string `json:"group"`
Name string `json:"name"`
Version string `json:"version"`
Properties []nativeImageCPE `json:"properties"`
}
type nativeImageCPE struct {
Name string `json:"name"`
Value string `json:"value"`
}
type nativeImage interface {
fetchPkgs() ([]pkg.Package, error)
fetchPkgs() ([]pkg.Package, []artifact.Relationship, error)
}
type nativeImageElf struct {
@@ -113,40 +92,12 @@ func (c *nativeImageCataloger) Name() string {
return nativeImageCatalogerName
}
// getPackage returns the package given within a NativeImageComponent.
func getPackage(component nativeImageComponent) pkg.Package {
var cpes []cpe.CPE
for _, property := range component.Properties {
c, err := cpe.New(property.Value, cpe.DeclaredSource)
if err != nil {
log.Debugf("unable to parse Attributes: %v", err)
continue
}
cpes = append(cpes, c)
}
return pkg.Package{
Name: component.Name,
Version: component.Version,
Language: pkg.Java,
Type: pkg.GraalVMNativeImagePkg,
FoundBy: nativeImageCatalogerName,
Metadata: pkg.JavaArchive{
PomProperties: &pkg.JavaPomProperties{
GroupID: component.Group,
},
},
CPEs: cpes,
}
}
// decompressSbom returns the packages given within a native image executable's SBOM.
func decompressSbom(dataBuf []byte, sbomStart uint64, lengthStart uint64) ([]pkg.Package, error) {
var pkgs []pkg.Package
func decompressSbom(dataBuf []byte, sbomStart uint64, lengthStart uint64) ([]pkg.Package, []artifact.Relationship, error) {
lengthEnd := lengthStart + 8
bufLen := len(dataBuf)
if lengthEnd > uint64(bufLen) {
return nil, errors.New("the 'sbom_length' symbol overflows the binary")
return nil, nil, errors.New("the 'sbom_length' symbol overflows the binary")
}
length := dataBuf[lengthStart:lengthEnd]
@@ -154,39 +105,31 @@ func decompressSbom(dataBuf []byte, sbomStart uint64, lengthStart uint64) ([]pkg
var storedLength uint64
err := binary.Read(p, binary.LittleEndian, &storedLength)
if err != nil {
return nil, fmt.Errorf("could not read from binary file: %w", err)
return nil, nil, fmt.Errorf("could not read from binary file: %w", err)
}
log.WithFields("len", storedLength).Trace("found java native-image SBOM")
sbomEnd := sbomStart + storedLength
if sbomEnd > uint64(bufLen) {
return nil, errors.New("the sbom symbol overflows the binary")
return nil, nil, errors.New("the sbom symbol overflows the binary")
}
sbomCompressed := dataBuf[sbomStart:sbomEnd]
p = bytes.NewBuffer(sbomCompressed)
gzreader, err := gzip.NewReader(p)
if err != nil {
return nil, fmt.Errorf("could not decompress the java native-image SBOM: %w", err)
return nil, nil, fmt.Errorf("could not decompress the java native-image SBOM: %w", err)
}
output, err := io.ReadAll(gzreader)
sbom, _, _, err := cyclonedxjson.NewFormatDecoder().Decode(gzreader)
if err != nil {
return nil, fmt.Errorf("could not read the java native-image SBOM: %w", err)
return nil, nil, fmt.Errorf("could not unmarshal the java native-image SBOM: %w", err)
}
var sbomContent nativeImageCycloneDX
err = json.Unmarshal(output, &sbomContent)
if err != nil {
return nil, fmt.Errorf("could not unmarshal the java native-image SBOM: %w", err)
}
for _, component := range sbomContent.Components {
p := getPackage(component)
var pkgs []pkg.Package
for p := range sbom.Artifacts.Packages.Enumerate() {
pkgs = append(pkgs, p)
}
return pkgs, nil
return pkgs, sbom.Relationships, nil
}
// fileError logs an error message when an executable cannot be read.
@@ -294,7 +237,7 @@ func newPE(filename string, r io.ReaderAt) (nativeImage, error) {
}
// fetchPkgs obtains the packages given in the binary.
func (ni nativeImageElf) fetchPkgs() (pkgs []pkg.Package, retErr error) {
func (ni nativeImageElf) fetchPkgs() (pkgs []pkg.Package, relationships []artifact.Relationship, retErr error) {
defer func() {
if r := recover(); r != nil {
// this can happen in cases where a malformed binary is passed in can be initially parsed, but not
@@ -310,10 +253,10 @@ func (ni nativeImageElf) fetchPkgs() (pkgs []pkg.Package, retErr error) {
si, err := bi.Symbols()
if err != nil {
return nil, fmt.Errorf("no symbols found in binary: %w", err)
return nil, nil, fmt.Errorf("no symbols found in binary: %w", err)
}
if si == nil {
return nil, errors.New(nativeImageMissingSymbolsError)
return nil, nil, errors.New(nativeImageMissingSymbolsError)
}
for _, s := range si {
switch s.Name {
@@ -326,16 +269,16 @@ func (ni nativeImageElf) fetchPkgs() (pkgs []pkg.Package, retErr error) {
}
}
if sbom.Value == 0 || sbomLength.Value == 0 || svmVersion.Value == 0 {
return nil, errors.New(nativeImageMissingSymbolsError)
return nil, nil, errors.New(nativeImageMissingSymbolsError)
}
dataSection := bi.Section(".data")
if dataSection == nil {
return nil, fmt.Errorf("no .data section found in binary: %w", err)
return nil, nil, fmt.Errorf("no .data section found in binary: %w", err)
}
dataSectionBase := dataSection.SectionHeader.Addr
data, err := dataSection.Data()
if err != nil {
return nil, fmt.Errorf("cannot read the .data section: %w", err)
return nil, nil, fmt.Errorf("cannot read the .data section: %w", err)
}
sbomLocation := sbom.Value - dataSectionBase
lengthLocation := sbomLength.Value - dataSectionBase
@@ -344,7 +287,7 @@ func (ni nativeImageElf) fetchPkgs() (pkgs []pkg.Package, retErr error) {
}
// fetchPkgs obtains the packages from a Native Image given as a Mach O file.
func (ni nativeImageMachO) fetchPkgs() (pkgs []pkg.Package, retErr error) {
func (ni nativeImageMachO) fetchPkgs() (pkgs []pkg.Package, relationships []artifact.Relationship, retErr error) {
defer func() {
if r := recover(); r != nil {
// this can happen in cases where a malformed binary is passed in can be initially parsed, but not
@@ -359,7 +302,7 @@ func (ni nativeImageMachO) fetchPkgs() (pkgs []pkg.Package, retErr error) {
bi := ni.file
if bi.Symtab == nil {
return nil, errors.New(nativeImageMissingSymbolsError)
return nil, nil, errors.New(nativeImageMissingSymbolsError)
}
for _, s := range bi.Symtab.Syms {
switch s.Name {
@@ -372,17 +315,17 @@ func (ni nativeImageMachO) fetchPkgs() (pkgs []pkg.Package, retErr error) {
}
}
if sbom.Value == 0 || sbomLength.Value == 0 || svmVersion.Value == 0 {
return nil, errors.New(nativeImageMissingSymbolsError)
return nil, nil, errors.New(nativeImageMissingSymbolsError)
}
dataSegment := bi.Segment("__DATA")
if dataSegment == nil {
return nil, nil
return nil, nil, nil
}
dataBuf, err := dataSegment.Data()
if err != nil {
log.Tracef("cannot obtain buffer from data segment")
return nil, nil
return nil, nil, nil
}
sbomLocation := sbom.Value - dataSegment.Addr
lengthLocation := sbomLength.Value - dataSegment.Addr
@@ -494,7 +437,7 @@ func (ni nativeImagePE) fetchSbomSymbols(content *exportContentPE) {
}
// fetchPkgs obtains the packages from a Native Image given as a PE file.
func (ni nativeImagePE) fetchPkgs() (pkgs []pkg.Package, retErr error) {
func (ni nativeImagePE) fetchPkgs() (pkgs []pkg.Package, relationships []artifact.Relationship, retErr error) {
defer func() {
if r := recover(); r != nil {
// this can happen in cases where a malformed binary is passed in can be initially parsed, but not
@@ -506,32 +449,32 @@ func (ni nativeImagePE) fetchPkgs() (pkgs []pkg.Package, retErr error) {
content, err := ni.fetchExportContent()
if err != nil {
log.Debugf("could not fetch the content of the export directory entry: %v", err)
return nil, err
return nil, nil, err
}
ni.fetchSbomSymbols(content)
if content.addressOfSbom == uint32(0) || content.addressOfSbomLength == uint32(0) || content.addressOfSvmVersion == uint32(0) {
return nil, errors.New(nativeImageMissingSymbolsError)
return nil, nil, errors.New(nativeImageMissingSymbolsError)
}
functionsBase := content.addressOfFunctions - ni.exportSymbols.VirtualAddress
sbomOffset := content.addressOfSbom
sbomAddress, err := ni.fetchExportFunctionPointer(functionsBase, sbomOffset)
if err != nil {
return nil, fmt.Errorf("could not fetch SBOM pointer from exported functions: %w", err)
return nil, nil, fmt.Errorf("could not fetch SBOM pointer from exported functions: %w", err)
}
sbomLengthOffset := content.addressOfSbomLength
sbomLengthAddress, err := ni.fetchExportFunctionPointer(functionsBase, sbomLengthOffset)
if err != nil {
return nil, fmt.Errorf("could not fetch SBOM length pointer from exported functions: %w", err)
return nil, nil, fmt.Errorf("could not fetch SBOM length pointer from exported functions: %w", err)
}
bi := ni.file
dataSection := bi.Section(".data")
if dataSection == nil {
return nil, nil
return nil, nil, nil
}
dataBuf, err := dataSection.Data()
if err != nil {
log.Tracef("cannot obtain buffer from the java native-image .data section")
return nil, nil
return nil, nil, nil
}
sbomLocation := sbomAddress - dataSection.VirtualAddress
lengthLocation := sbomLengthAddress - dataSection.VirtualAddress
@@ -540,8 +483,9 @@ func (ni nativeImagePE) fetchPkgs() (pkgs []pkg.Package, retErr error) {
}
// fetchPkgs provides the packages available in a UnionReader.
func fetchPkgs(reader unionreader.UnionReader, filename string) []pkg.Package {
func fetchPkgs(reader unionreader.UnionReader, filename string) ([]pkg.Package, []artifact.Relationship) {
var pkgs []pkg.Package
var relationships []artifact.Relationship
imageFormats := []func(string, io.ReaderAt) (nativeImage, error){newElf, newMachO, newPE}
// NOTE: multiple readers are returned to cover universal binaries, which are files
@@ -549,7 +493,7 @@ func fetchPkgs(reader unionreader.UnionReader, filename string) []pkg.Package {
readers, err := unionreader.GetReaders(reader)
if err != nil {
log.Debugf("failed to open the java native-image binary: %v", err)
return nil
return nil, nil
}
for _, r := range readers {
for _, makeNativeImage := range imageFormats {
@@ -560,47 +504,51 @@ func fetchPkgs(reader unionreader.UnionReader, filename string) []pkg.Package {
if ni == nil {
continue
}
newPkgs, err := ni.fetchPkgs()
newPkgs, newRelationships, err := ni.fetchPkgs()
if err != nil {
log.Tracef("unable to extract SBOM from possible java native-image %s: %v", filename, err)
continue
}
pkgs = append(pkgs, newPkgs...)
relationships = append(relationships, newRelationships...)
}
}
return pkgs
return pkgs, relationships
}
// Catalog attempts to find any native image executables reachable from a resolver.
func (c *nativeImageCataloger) Catalog(_ context.Context, resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
var pkgs []pkg.Package
var relationships []artifact.Relationship
fileMatches, err := resolver.FilesByMIMEType(mimetype.ExecutableMIMETypeSet.List()...)
if err != nil {
return pkgs, nil, fmt.Errorf("failed to find binaries by mime types: %w", err)
}
for _, location := range fileMatches {
newPkgs, err := processLocation(location, resolver)
newPkgs, newRelationships, err := processLocation(location, resolver)
if err != nil {
return nil, nil, err
}
pkgs = append(pkgs, newPkgs...)
relationships = append(relationships, newRelationships...)
}
return pkgs, nil, nil
return pkgs, relationships, nil
}
func processLocation(location file.Location, resolver file.Resolver) ([]pkg.Package, error) {
func processLocation(location file.Location, resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
readerCloser, err := resolver.FileContentsByLocation(location)
if err != nil {
log.Debugf("error opening file: %v", err)
return nil, nil
return nil, nil, nil
}
defer internal.CloseAndLogError(readerCloser, location.RealPath)
reader, err := unionreader.GetUnionReader(readerCloser)
if err != nil {
return nil, err
return nil, nil, err
}
return fetchPkgs(reader, location.RealPath), nil
pkgs, relationships := fetchPkgs(reader, location.RealPath)
return pkgs, relationships, nil
}
@@ -5,6 +5,7 @@ import (
"bytes"
"compress/gzip"
"encoding/binary"
"fmt"
"io"
"os"
"path"
@@ -12,6 +13,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/internal/unionreader"
"github.com/anchore/syft/syft/pkg"
@@ -40,10 +42,11 @@ func TestParseNativeImage(t *testing.T) {
assert.NoError(t, err)
parsed := false
readers, err := unionreader.GetReaders(reader)
assert.NoError(t, err)
for _, r := range readers {
ni, err := test.newFn(test.fixture, r)
assert.NoError(t, err)
_, err = ni.fetchPkgs()
_, _, err = ni.fetchPkgs()
if err == nil {
t.Fatalf("should have failed to extract SBOM.")
}
@@ -60,77 +63,205 @@ func TestParseNativeImage(t *testing.T) {
}
func TestParseNativeImageSbom(t *testing.T) {
const (
nettyPurl = "pkg:maven/io.netty/netty-codec-http2@4.1.104.Final"
micronautPurl = "pkg:maven/io.micronaut/core@4.2.3"
mainAppPurl = "pkg:maven/com.oracle/main-test-app@1.0-SNAPSHOT"
)
mainAppPkg := makePackage("main-test-app", "1.0-SNAPSHOT", mainAppPurl, []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "app",
Product: "main-test-app",
Version: "1.0-SNAPSHOT",
},
Source: "declared",
},
})
nettyPkg := makePackage("netty-codec-http2", "4.1.73.Final", nettyPurl, []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "codec",
Product: "codec",
Version: "4.1.73.Final",
},
Source: "declared",
},
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "codec",
Product: "netty-codec-http2",
Version: "4.1.73.Final",
},
Source: "declared",
},
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "codec",
Product: "netty_codec_http2",
Version: "4.1.73.Final",
},
Source: "declared",
},
})
micronautPkg := makePackage("core", "4.2.3", micronautPurl, []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "core",
Product: "core",
Version: "4.2.3",
},
Source: "declared",
},
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "micronaut",
Product: "core",
Version: "4.2.3",
},
Source: "declared",
},
})
basicPkg := makePackage("basic-lib", "1.0", "", nil)
tests := []struct {
fixture string
expected []pkg.Package
fixture string
expectedPackages []pkg.Package
expectedRelations []artifact.Relationship
}{
{
fixture: "test-fixtures/graalvm-sbom/micronaut.json",
expected: []pkg.Package{
fixture: "test-fixtures/graalvm-sbom/micronaut.json",
expectedPackages: []pkg.Package{nettyPkg, micronautPkg, basicPkg, mainAppPkg},
expectedRelations: []artifact.Relationship{
{
Name: "netty-codec-http2",
Version: "4.1.73.Final",
Language: pkg.Java,
Type: pkg.GraalVMNativeImagePkg,
FoundBy: nativeImageCatalogerName,
Metadata: pkg.JavaArchive{
PomProperties: &pkg.JavaPomProperties{
GroupID: "io.netty",
},
},
CPEs: []cpe.CPE{
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "codec",
Product: "codec",
Version: "4.1.73.Final",
},
Source: "declared",
},
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "codec",
Product: "netty-codec-http2",
Version: "4.1.73.Final",
},
Source: "declared",
},
{
Attributes: cpe.Attributes{
Part: "a",
Vendor: "codec",
Product: "netty_codec_http2",
Version: "4.1.73.Final",
},
Source: "declared",
},
},
From: nettyPkg,
To: micronautPkg,
Type: artifact.DependencyOfRelationship,
},
},
},
}
for _, test := range tests {
t.Run(path.Base(test.fixture), func(t *testing.T) {
// Create a buffer to resemble a compressed SBOM in a native image.
sbom, err := os.ReadFile(test.fixture)
assert.NoError(t, err)
var b bytes.Buffer
writebytes := bufio.NewWriter(&b)
z := gzip.NewWriter(writebytes)
_, err = z.Write(sbom)
assert.NoError(t, err)
_ = z.Close()
_ = writebytes.Flush()
compressedsbom := b.Bytes()
sbomlength := uint64(len(compressedsbom))
_ = binary.Write(writebytes, binary.LittleEndian, sbomlength)
_ = writebytes.Flush()
compressedsbom = b.Bytes()
actual, err := decompressSbom(compressedsbom, 0, sbomlength)
assert.NoError(t, err)
assert.Equal(t, test.expected, actual)
compressed, length := createCompressedSbom(t, test.fixture)
actualPkgs, actualRels, err := decompressSbom(compressed, 0, length)
if err != nil {
t.Fatal(err)
}
verifyPackages(t, test.expectedPackages, actualPkgs)
verifyRelationships(t, test.expectedRelations, actualRels)
})
}
}
// makePackage makes a package using the data that we know must be in the parsed package
func makePackage(name, version, purl string, cpes []cpe.CPE) pkg.Package {
p := pkg.Package{
Name: name,
Version: version,
CPEs: cpes,
PURL: purl,
}
return p
}
// createCompressedSbom creates a compressed a buffer to resemble a compressed SBOM in a native image.
func createCompressedSbom(t *testing.T, filename string) ([]byte, uint64) {
sbom, err := os.ReadFile(filename)
if err != nil {
t.Fatal(err)
}
var b bytes.Buffer
w := bufio.NewWriter(&b)
z := gzip.NewWriter(w)
if _, err := z.Write(sbom); err != nil {
t.Fatal(err)
}
z.Close()
w.Flush()
compressedSbom := b.Bytes()
sbomLength := uint64(len(compressedSbom))
if err := binary.Write(w, binary.LittleEndian, sbomLength); err != nil {
t.Fatal(err)
}
w.Flush()
return b.Bytes(), sbomLength
}
func verifyPackages(t *testing.T, expected, actual []pkg.Package) {
expectedPkgMap := buildPackageMap(expected)
actualPkgMap := buildPackageMap(actual)
for name, expectedPkg := range expectedPkgMap {
actualPkg, exists := actualPkgMap[name]
if !exists {
t.Errorf("Expected package %s not found in actual packages", name)
continue
}
verifyPackageFields(t, expectedPkg, actualPkg)
}
}
func buildPackageMap(packages []pkg.Package) map[string]pkg.Package {
pkgMap := make(map[string]pkg.Package)
for _, p := range packages {
pkgMap[p.Name] = p
}
return pkgMap
}
func verifyPackageFields(t *testing.T, expected, actual pkg.Package) {
assert.Equal(t, expected.Name, actual.Name)
assert.Equal(t, expected.Version, actual.Version)
assert.Equal(t, expected.FoundBy, actual.FoundBy)
assert.Equal(t, expected.PURL, actual.PURL)
assert.ElementsMatch(t, expected.CPEs, actual.CPEs)
}
func verifyRelationships(t *testing.T, expected, actual []artifact.Relationship) {
expectedRelMap := buildRelationshipMap(expected)
actualRelMap := buildRelationshipMap(actual)
for key, expectedRels := range expectedRelMap {
actualRels, exists := actualRelMap[key]
if !exists {
t.Errorf("Expected relationship %s not found in actual relationships", key)
continue
}
verifyRelationshipFields(t, expectedRels, actualRels)
}
}
func buildRelationshipMap(relationships []artifact.Relationship) map[string][]artifact.Relationship {
relMap := make(map[string][]artifact.Relationship)
for _, rel := range relationships {
// we cannot control the id, so use the names instead
key := fmt.Sprintf("%s->%s", rel.From.(pkg.Package).Name, rel.To.(pkg.Package).Name)
relMap[key] = append(relMap[key], rel)
}
return relMap
}
func verifyRelationshipFields(t *testing.T, expected, actual []artifact.Relationship) {
assert.Equal(t, len(expected), len(actual))
for i := range expected {
assert.Equal(t, expected[i].Type, actual[i].Type)
}
}
@@ -135,9 +135,14 @@ func (r *Resolver) resolveProperty(ctx context.Context, resolutionContext []*Pro
return value, nil
}
var resolvingParents []*Project
for _, pom := range resolutionContext {
current := pom
for parentDepth := 0; current != nil; parentDepth++ {
if slices.Contains(resolvingParents, current) {
log.WithFields("property", propertyExpression, "mavenID", r.resolveID(ctx, resolvingProperties, resolvingParents...)).Error("got circular reference while resolving property")
break // some sort of circular reference -- we've already seen this project
}
if r.cfg.MaxParentRecursiveDepth > 0 && parentDepth > r.cfg.MaxParentRecursiveDepth {
return "", fmt.Errorf("maximum parent recursive depth (%v) reached resolving property: %v", r.cfg.MaxParentRecursiveDepth, propertyExpression)
}
@@ -146,6 +151,7 @@ func (r *Resolver) resolveProperty(ctx context.Context, resolutionContext []*Pro
return r.resolveExpression(ctx, resolutionContext, value, resolvingProperties) // property values can contain expressions
}
}
resolvingParents = append(resolvingParents, current)
current, err = r.resolveParent(ctx, current, resolvingProperties...)
if err != nil {
return "", err
@@ -271,13 +277,12 @@ func (r *Resolver) resolveID(ctx context.Context, resolvingProperties []string,
artifactID := r.resolvePropertyValue(ctx, pom.ArtifactID, resolvingProperties, resolutionContext...)
version := r.resolvePropertyValue(ctx, pom.Version, resolvingProperties, resolutionContext...)
if pom.Parent != nil {
if groupID == "" {
// groupId and version are able to be inherited from the parent, but importantly: not artifactId. see:
// https://maven.apache.org/guides/introduction/introduction-to-the-pom.html#the-solution
if groupID == "" && deref(pom.GroupID) == "" {
groupID = r.resolvePropertyValue(ctx, pom.Parent.GroupID, resolvingProperties, resolutionContext...)
}
if artifactID == "" {
artifactID = r.resolvePropertyValue(ctx, pom.Parent.ArtifactID, resolvingProperties, resolutionContext...)
}
if version == "" {
if version == "" && deref(pom.Version) == "" {
version = r.resolvePropertyValue(ctx, pom.Parent.Version, resolvingProperties, resolutionContext...)
}
}
@@ -243,6 +243,13 @@ func Test_mavenResolverRemote(t *testing.T) {
expression: "${project.one}",
expected: "1",
},
{
groupID: "my.org", // this particular package has a circular reference
artifactID: "circular",
version: "1.2.3",
expression: "${unresolved}",
expected: "",
},
}
for _, test := range tests {
@@ -312,6 +319,27 @@ func Test_relativePathParent(t *testing.T) {
require.Equal(t, "", id.Version)
},
},
{
name: "circular resolving ID variables",
pom: "circular-1/pom.xml",
validate: func(t *testing.T, r *Resolver, pom *Project) {
require.NotNil(t, pom)
id := r.ResolveID(ctx, pom)
// version should be resolved, but not artifactId
require.Equal(t, "1.2.3", id.Version)
require.Equal(t, "", id.ArtifactID)
},
},
{
name: "circular parent only",
pom: "circular-2/pom.xml",
validate: func(t *testing.T, r *Resolver, pom *Project) {
require.NotNil(t, pom)
id := r.ResolveID(ctx, pom)
require.Equal(t, "", id.Version)
require.Equal(t, "something", id.ArtifactID)
},
},
}
for _, test := range tests {
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<parent>
<groupId>my.org</groupId>
<artifactId>circular</artifactId>
<version>1.2.3</version>
</parent>
</project>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>something</artifactId>
<version>${unresolvable}</version>
<parent>
<groupId>my.org</groupId>
<artifactId>circular</artifactId>
<version>1.2.3</version>
</parent>
</project>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>circular</artifactId>
<version>1.2.3</version>
<parent>
<groupId>my.org</groupId>
<artifactId>circular</artifactId>
<version>1.2.3</version>
</parent>
</project>
@@ -1,13 +1,32 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"specVersion": "1.6",
"version": 1,
"serialNumber": "urn:uuid:43538af4-f715-3d85-9629-336fdd3790ad",
"metadata": {
"component": {
"type": "library",
"group": "com.test",
"name": "main-test-app",
"version": "1.0-SNAPSHOT",
"purl": "pkg:maven/com.oracle/main-test-app@1.0-SNAPSHOT",
"bom-ref": "pkg:maven/com.oracle/main-test-app@1.0-SNAPSHOT",
"properties": [
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:app:main-test-app:1.0-SNAPSHOT:*:*:*:*:*:*:*"
}
]
}
},
"components": [
{
"type": "library",
"group": "io.netty",
"name": "netty-codec-http2",
"version": "4.1.73.Final",
"purl": "pkg:maven/io.netty/netty-codec-http2@4.1.104.Final",
"bom-ref": "pkg:maven/io.netty/netty-codec-http2@4.1.104.Final",
"properties": [
{
"name": "syft:cpe23",
@@ -22,7 +41,38 @@
"value": "cpe:2.3:a:codec:netty_codec_http2:4.1.73.Final:*:*:*:*:*:*:*"
}
]
},
{
"type": "library",
"group": "io.micronaut",
"name": "core",
"version": "4.2.3",
"purl": "pkg:maven/io.micronaut/core@4.2.3",
"bom-ref": "pkg:maven/io.micronaut/core@4.2.3",
"properties": [
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:core:core:4.2.3:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:micronaut:core:4.2.3:*:*:*:*:*:*:*"
}
]
},
{
"type": "library",
"group": "org.example",
"name": "basic-lib",
"version": "1.0"
}
],
"serialNumber": "urn:uuid:43538af4-f715-3d85-9629-336fdd3790ad"
}
"dependencies": [
{
"ref": "pkg:maven/io.micronaut/core@4.2.3",
"dependsOn": [
"pkg:maven/io.netty/netty-codec-http2@4.1.104.Final"
]
}
]
}
+8 -2
View File
@@ -3,8 +3,9 @@ package javascript
const npmBaseURL = "https://registry.npmjs.org"
type CatalogerConfig struct {
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
NPMBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
NPMBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
IncludeDevDependencies bool `json:"include-dev-dependencies" yaml:"include-dev-dependencies" mapstructure:"include-dev-dependencies"`
}
func DefaultCatalogerConfig() CatalogerConfig {
@@ -25,3 +26,8 @@ func (j CatalogerConfig) WithNpmBaseURL(input string) CatalogerConfig {
}
return j
}
func (j CatalogerConfig) WithIncludeDevDependencies(input bool) CatalogerConfig {
j.IncludeDevDependencies = input
return j
}
@@ -29,6 +29,7 @@ type lockDependency struct {
Version string `json:"version"`
Resolved string `json:"resolved"`
Integrity string `json:"integrity"`
Dev bool `json:"dev"`
}
type lockPackage struct {
@@ -37,6 +38,7 @@ type lockPackage struct {
Resolved string `json:"resolved"`
Integrity string `json:"integrity"`
License packageLockLicense `json:"license"`
Dev bool `json:"dev"`
}
// packageLockLicense
@@ -74,6 +76,11 @@ func (a genericPackageLockAdapter) parsePackageLock(_ context.Context, resolver
if lock.LockfileVersion == 1 {
for name, pkgMeta := range lock.Dependencies {
// skip packages that are only present as a dev dependency
if !a.cfg.IncludeDevDependencies && pkgMeta.Dev {
continue
}
pkgs = append(pkgs, newPackageLockV1Package(a.cfg, resolver, reader.Location, name, pkgMeta))
}
}
@@ -87,6 +94,11 @@ func (a genericPackageLockAdapter) parsePackageLock(_ context.Context, resolver
name = pkgMeta.Name
}
// skip packages that are only present as a dev dependency
if !a.cfg.IncludeDevDependencies && pkgMeta.Dev {
continue
}
// handles alias names
if pkgMeta.Name != "" {
name = pkgMeta.Name
@@ -9,6 +9,9 @@
"version": "6.14.6",
"dependencies": {
"@types/react": "^18.0.9"
},
"devDependencies": {
"async": "^3.2.4"
}
},
"node_modules/@types/prop-types": {
@@ -39,6 +42,12 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha1-TdysNxjXh8+d8NG30VAzklyPKfI=",
"license": "MIT"
},
"node_modules/async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
"dev": true
}
},
"dependencies": {
@@ -66,6 +75,12 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha1-TdysNxjXh8+d8NG30VAzklyPKfI="
},
"async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
"dev": true
}
}
}
@@ -9,6 +9,9 @@
"version": "1.0.0",
"dependencies": {
"@types/react": "^18.0.9"
},
"devDependencies": {
"async": "^3.2.4"
}
},
"node_modules/@types/prop-types": {
@@ -35,6 +38,12 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
},
"node_modules/async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
"dev": true
}
}
}
@@ -76,6 +76,12 @@
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
},
"node_modules/async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
"dev": true
}
}
}
@@ -1,3 +1,5 @@
FROM alpine@sha256:c5c5fda71656f28e49ac9c5416b3643eaa6a108a8093151d6d1afc9463be8e33
RUN rm -rf /lib/apk/db/installed
COPY . /home/files
# add a circular reference that will result in a failure while executing FindByGlob:
RUN mkdir -p /etc/alternatives && ln -s /etc/alternatives/java2 /etc/alternatives/java && ln -s /etc/alternatives/java /etc/alternatives/java2
+1
View File
@@ -22,6 +22,7 @@ func Test_Unknowns(t *testing.T) {
assertInOutput(`no package identified in executable file`),
assertInOutput(`unable to read files from java archive`),
assertInOutput(`no package identified in archive`),
assertInOutput(`cycle during symlink resolution`),
assertSuccessfulReturnCode,
},
},