mirror of
https://github.com/anchore/syft.git
synced 2026-10-30 14:02:26 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0bfd2f98a | ||
|
|
f6605a3817 | ||
|
|
5e2723187d | ||
|
|
f44b709542 | ||
|
|
2792013eb2 | ||
|
|
3b951648a8 | ||
|
|
e4d9ccde47 | ||
|
|
3c5a71156e | ||
|
|
ed66988928 |
@@ -39,7 +39,7 @@ jobs:
|
||||
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
|
||||
echo "result=$OUTPUT" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
- uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
||||
with:
|
||||
name: benchmark-test-results
|
||||
path: test/results/**/*
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 #v3.28.9
|
||||
uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d #v3.28.10
|
||||
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@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 #v3.28.9
|
||||
uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d #v3.28.10
|
||||
|
||||
# ℹ️ 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@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 #v3.28.9
|
||||
uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d #v3.28.10
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
app_id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f #v7.0.6
|
||||
- uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 #v7.0.7
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
app_id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f #v7.0.6
|
||||
- uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 #v7.0.7
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
app_id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f #v7.0.6
|
||||
- uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 #v7.0.7
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
|
||||
@@ -139,7 +139,7 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@v3.8.0
|
||||
uses: sigstore/cosign-installer@v3.8.1
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
|
||||
|
||||
|
||||
+1
-1
@@ -581,7 +581,7 @@ tasks:
|
||||
- "{{ .NEXT_VERSION }}"
|
||||
cmds:
|
||||
- "{{ .TOOL_DIR }}/chronicle -vv -n --version-file {{ .NEXT_VERSION }} > {{ .CHANGELOG }}"
|
||||
- "{{ .TOOL_DIR }}/glow {{ .CHANGELOG }}"
|
||||
- "{{ .TOOL_DIR }}/glow -w 0 {{ .CHANGELOG }}"
|
||||
|
||||
|
||||
## Release targets #################################
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
@@ -12,6 +13,10 @@ import (
|
||||
// CloseAndLogError closes the given io.Closer and reports any errors found as a warning in the log
|
||||
func CloseAndLogError(closer io.Closer, location string) {
|
||||
if err := closer.Close(); err != nil {
|
||||
// suppress "file already closed" log messages
|
||||
if errors.Is(err, fs.ErrClosed) {
|
||||
return
|
||||
}
|
||||
log.Debugf("unable to close file for location=%q: %+v", location, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,16 +70,27 @@ func ToFormatModel(s sbom.SBOM) *cyclonedx.BOM {
|
||||
continue
|
||||
}
|
||||
metadata = &fileMetadata
|
||||
|
||||
// Digests
|
||||
var digests []file.Digest
|
||||
if digestsForLocation, exists := artifacts.FileDigests[coordinate]; exists {
|
||||
digests = digestsForLocation
|
||||
}
|
||||
|
||||
cdxHashes := digestsToHashes(digests)
|
||||
components = append(components, cyclonedx.Component{
|
||||
BOMRef: string(coordinate.ID()),
|
||||
Type: cyclonedx.ComponentTypeFile,
|
||||
Name: metadata.Path,
|
||||
Hashes: slicePtr(digestsToHashes(artifacts.FileDigests[coordinate])),
|
||||
Hashes: &cdxHashes,
|
||||
})
|
||||
}
|
||||
cdxBOM.Components = slicePtr(components)
|
||||
cdxBOM.Components = &components
|
||||
|
||||
cdxBOM.Dependencies = slicePtr(toDependencies(s.Relationships))
|
||||
dependencies := toDependencies(s.Relationships)
|
||||
if len(dependencies) > 0 {
|
||||
cdxBOM.Dependencies = &dependencies
|
||||
}
|
||||
|
||||
return cdxBOM
|
||||
}
|
||||
@@ -266,7 +277,14 @@ func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependenc
|
||||
func toBomProperties(srcMetadata source.Description) *[]cyclonedx.Property {
|
||||
metadata, ok := srcMetadata.Metadata.(source.ImageMetadata)
|
||||
if ok {
|
||||
return slicePtr(helpers.EncodeProperties(metadata.Labels, "syft:image:labels"))
|
||||
props := helpers.EncodeProperties(metadata.Labels, "syft:image:labels")
|
||||
// return nil if props is nil to avoid creating a pointer to a nil slice,
|
||||
// which results in a null JSON value that does not comply with the CycloneDX schema.
|
||||
// https://github.com/anchore/grype/issues/1759
|
||||
if props == nil {
|
||||
return nil
|
||||
}
|
||||
return &props
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -326,14 +344,3 @@ func toBomDescriptorComponent(srcMetadata source.Description) *cyclonedx.Compone
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Every slice pointer needs to either be a valid slice or nil,
|
||||
// otherwise we will create a pointer that is not nil but references
|
||||
// a nil slice, which results in a `null` JSON value that does not
|
||||
// comply with the CycloneDX schema. See: https://github.com/anchore/grype/issues/1759
|
||||
func slicePtr[T any](values []T) *[]T {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &values
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/format/internal/cyclonedxutil"
|
||||
"github.com/anchore/syft/syft/format/internal/testutil"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -28,31 +27,6 @@ func getEncoder(t testing.TB) sbom.FormatEncoder {
|
||||
return enc
|
||||
}
|
||||
|
||||
func Test_noTypedNils(t *testing.T) {
|
||||
s := sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
FileMetadata: map[file.Coordinates]file.Metadata{},
|
||||
FileDigests: map[file.Coordinates][]file.Digest{},
|
||||
},
|
||||
}
|
||||
c := file.NewCoordinates("/dev/null", "123")
|
||||
s.Artifacts.FileMetadata[c] = file.Metadata{
|
||||
Path: "/dev/null",
|
||||
}
|
||||
s.Artifacts.FileDigests[c] = []file.Digest{}
|
||||
|
||||
enc, err := NewFormatEncoderWithConfig(EncoderConfig{
|
||||
Version: "1.6",
|
||||
Pretty: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
contents := bytes.Buffer{}
|
||||
err = enc.Encode(&contents, s)
|
||||
require.NoError(t, err)
|
||||
require.NotContains(t, contents.String(), `"hashes": null`)
|
||||
}
|
||||
|
||||
func TestPrettyOutput(t *testing.T) {
|
||||
run := func(opt bool) string {
|
||||
enc, err := NewFormatEncoderWithConfig(EncoderConfig{
|
||||
|
||||
@@ -171,18 +171,36 @@ func parseSystemReleaseCPE(contents string) (*Release, error) {
|
||||
}
|
||||
|
||||
// example: "CentOS release 6.10 (Final)"
|
||||
var redhatReleaseMatcher = regexp.MustCompile(`(.*?)\srelease\s(\d\.\d+)`)
|
||||
var redhatReleaseMatcher = regexp.MustCompile(`(?P<name>.*?)\srelease\s(?P<version>(?P<versionid>\d\.\d+).*)`)
|
||||
|
||||
// parseRedhatRelease is a fallback parsing method for determining distro information in older redhat versions
|
||||
func parseRedhatRelease(contents string) (*Release, error) {
|
||||
matches := redhatReleaseMatcher.FindAllStringSubmatch(contents, -1)
|
||||
for _, match := range matches {
|
||||
if len(match) < 3 {
|
||||
continue
|
||||
}
|
||||
return simpleRelease(match[1], strings.ToLower(match[1]), match[2], ""), nil
|
||||
contents = strings.TrimSpace(contents)
|
||||
matches := internal.MatchNamedCaptureGroups(redhatReleaseMatcher, contents)
|
||||
name := matches["name"]
|
||||
version := matches["version"]
|
||||
versionID := matches["versionid"]
|
||||
if name == "" || versionID == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
id := strings.ToLower(name)
|
||||
switch {
|
||||
case strings.HasPrefix(id, "red hat enterprise linux"):
|
||||
id = "rhel"
|
||||
case strings.HasPrefix(id, "centos"):
|
||||
// ignore the parenthetical version information
|
||||
version = versionID
|
||||
}
|
||||
|
||||
return &Release{
|
||||
PrettyName: contents,
|
||||
Name: name,
|
||||
ID: id,
|
||||
IDLike: []string{id},
|
||||
Version: version,
|
||||
VersionID: versionID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func simpleRelease(prettyName, name, version, cpe string) *Release {
|
||||
|
||||
@@ -107,7 +107,7 @@ func TestIdentifyRelease(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/os/redhat",
|
||||
fixture: "test-fixtures/os/redhat/from-os-release",
|
||||
release: &Release{
|
||||
PrettyName: "Red Hat Enterprise Linux Server 7.3 (Maipo)",
|
||||
Name: "Red Hat Enterprise Linux Server",
|
||||
@@ -120,6 +120,17 @@ func TestIdentifyRelease(t *testing.T) {
|
||||
CPEName: "cpe:/o:redhat:enterprise_linux:7.3:GA:server",
|
||||
},
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/os/redhat/from-redhat-release",
|
||||
release: &Release{
|
||||
PrettyName: "Red Hat Enterprise Linux release 8.10 (Ootpa)",
|
||||
Name: "Red Hat Enterprise Linux",
|
||||
ID: "rhel",
|
||||
IDLike: []string{"rhel"},
|
||||
Version: "8.10 (Ootpa)",
|
||||
VersionID: "8.10",
|
||||
},
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/os/ubuntu",
|
||||
release: &Release{
|
||||
@@ -266,8 +277,8 @@ func TestIdentifyRelease(t *testing.T) {
|
||||
{
|
||||
fixture: "test-fixtures/os/centos5",
|
||||
release: &Release{
|
||||
PrettyName: "CentOS",
|
||||
Name: "centos",
|
||||
PrettyName: "CentOS release 5.7 (Final)",
|
||||
Name: "CentOS",
|
||||
ID: "centos",
|
||||
IDLike: []string{"centos"},
|
||||
Version: "5.7",
|
||||
@@ -506,8 +517,8 @@ func TestParseRedhatRelease(t *testing.T) {
|
||||
fixture: "test-fixtures/os/centos5/etc/redhat-release",
|
||||
name: "Centos 5",
|
||||
release: &Release{
|
||||
PrettyName: "CentOS",
|
||||
Name: "centos",
|
||||
PrettyName: "CentOS release 5.7 (Final)",
|
||||
Name: "CentOS",
|
||||
ID: "centos",
|
||||
IDLike: []string{"centos"},
|
||||
Version: "5.7",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Red Hat Enterprise Linux release 8.10 (Ootpa)
|
||||
@@ -378,6 +378,12 @@
|
||||
"build-metrics": [
|
||||
"cpe:2.3:a:jenkins:build-metrics:*:*:*:*:*:jenkins:*:*"
|
||||
],
|
||||
"build-monitor": [
|
||||
"cpe:2.3:a:jenkins:build_monitor_view:*:*:*:*:*:jenkins:*:*"
|
||||
],
|
||||
"build-monitor-plugin": [
|
||||
"cpe:2.3:a:jenkins:build_monitor_view:*:*:*:*:*:jenkins:*:*"
|
||||
],
|
||||
"build-notifications": [
|
||||
"cpe:2.3:a:jenkins:build_notifications:*:*:*:*:*:jenkins:*:*"
|
||||
],
|
||||
@@ -7874,6 +7880,9 @@
|
||||
"aprils-super-functions-pack": [
|
||||
"cpe:2.3:a:april\\'s_super_functions_pack_project:april\\'s_super_functions_pack:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"apus-framework": [
|
||||
"cpe:2.3:a:apusthemes:superio:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"ar-for-wordpress": [
|
||||
"cpe:2.3:a:webandprint:ar:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -11847,6 +11856,9 @@
|
||||
"happyforms": [
|
||||
"cpe:2.3:a:happyforms:happyforms:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"hash-form": [
|
||||
"cpe:2.3:a:hashthemes:hash_form:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"hashbar-wp-notification-bar": [
|
||||
"cpe:2.3:a:hasthemes:hashbar:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -16581,6 +16593,9 @@
|
||||
"strategery-migrations": [
|
||||
"cpe:2.3:a:strategery_migrations_project:strategery_migrations:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"stray-quotes": [
|
||||
"cpe:2.3:a:unalignedcode:stray_random_quotes:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"stream": [
|
||||
"cpe:2.3:a:xwp:stream:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -16861,6 +16876,9 @@
|
||||
"the-moneytizer": [
|
||||
"cpe:2.3:a:themoneytizer:the_moneytizer:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"the-pack-addon": [
|
||||
"cpe:2.3:a:webangon:the_pack_elementor_addons:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"the-plus-addons-for-block-editor": [
|
||||
"cpe:2.3:a:posimyth:nexter_blocks:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -17381,8 +17399,8 @@
|
||||
"cpe:2.3:a:kaizencoders:url_shortify:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"usc-e-shop": [
|
||||
"cpe:2.3:a:collne:welcart:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:collne:welcart_e-commerce:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:collne:welcart_e-commerce:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:welcart:welcart_e-commerce:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"use-any-font": [
|
||||
"cpe:2.3:a:anyfont_plugin_project:anyfont:*:*:*:*:*:wordpress:*:*",
|
||||
@@ -19666,6 +19684,9 @@
|
||||
"wpb-advanced-faq": [
|
||||
"cpe:2.3:a:wpbean:wpb_advanced_faq:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wpb-elementor-addons": [
|
||||
"cpe:2.3:a:wpbean:wpb_elementor_addons:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wpb-show-core": [
|
||||
"cpe:2.3:a:wpb_show_core_project:wpb_show_core:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -19751,7 +19772,7 @@
|
||||
"cpe:2.3:a:wpfront:wpfront_user_role_editor:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wpfunnels": [
|
||||
"cpe:2.3:a:coderex:wpfunnels:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:getwpfunnels:wpfunnels:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wpgenious-job-listing": [
|
||||
"cpe:2.3:a:wpgenious:wpgenius_job_listing:*:*:*:*:*:wordpress:*:*"
|
||||
|
||||
@@ -55,22 +55,18 @@ func parsePackageJSON(_ context.Context, _ file.Resolver, _ *generic.Environment
|
||||
var pkgs []pkg.Package
|
||||
dec := json.NewDecoder(reader)
|
||||
|
||||
for {
|
||||
var p packageJSON
|
||||
if err := dec.Decode(&p); errors.Is(err, io.EOF) {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse package.json file: %w", err)
|
||||
}
|
||||
|
||||
// always create a package, regardless of having a valid name and/or version,
|
||||
// a compliance filter later will remove these packages based on compliance rules
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
newPackageJSONPackage(p, reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
)
|
||||
var p packageJSON
|
||||
if err := dec.Decode(&p); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, fmt.Errorf("failed to parse package.json file: %w", err)
|
||||
}
|
||||
|
||||
// always create a package, regardless of having a valid name and/or version,
|
||||
// a compliance filter later will remove these packages based on compliance rules
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
newPackageJSONPackage(p, reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
)
|
||||
|
||||
pkg.Sort(pkgs)
|
||||
|
||||
return pkgs, nil, nil
|
||||
|
||||
@@ -66,12 +66,8 @@ func (a genericPackageLockAdapter) parsePackageLock(_ context.Context, resolver
|
||||
dec := json.NewDecoder(reader)
|
||||
|
||||
var lock packageLock
|
||||
for {
|
||||
if err := dec.Decode(&lock); errors.Is(err, io.EOF) {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse package-lock.json file: %w", err)
|
||||
}
|
||||
if err := dec.Decode(&lock); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, nil, fmt.Errorf("failed to parse package-lock.json file: %w", err)
|
||||
}
|
||||
|
||||
if lock.LockfileVersion == 1 {
|
||||
|
||||
Reference in New Issue
Block a user