Compare commits

..
Author SHA1 Message Date
Keith Zantow 4c3e49957c chore: more lenient java groupID lookups
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-08-17 14:38:28 -04:00
38 changed files with 357 additions and 3006 deletions
@@ -29,7 +29,6 @@ jobs:
GOSIMPORTS_LATEST_VERSION=$(go list -m -json github.com/rinchsan/gosimports@latest 2>/dev/null | jq -r '.Version')
YAJSV_LATEST_VERSION=$(go list -m -json github.com/neilpa/yajsv@latest 2>/dev/null | jq -r '.Version')
COSIGN_LATEST_VERSION=$(go list -m -json github.com/sigstore/cosign/v2@latest 2>/dev/null | jq -r '.Version')
QUILL_LATEST_VERSION=$(go list -m -json github.com/anchore/quill@latest 2>/dev/null | jq -r '.Version')
GLOW_LATEST_VERSION=$(go list -m -json github.com/charmbracelet/glow@latest 2>/dev/null | jq -r '.Version')
# update version variables in the Makefile
@@ -40,7 +39,6 @@ jobs:
sed -r -i -e 's/^(GOSIMPORTS_VERSION := ).*/\1'${GOSIMPORTS_LATEST_VERSION}'/' Makefile
sed -r -i -e 's/^(YAJSV_VERSION := ).*/\1'${YAJSV_LATEST_VERSION}'/' Makefile
sed -r -i -e 's/^(COSIGN_VERSION := ).*/\1'${COSIGN_LATEST_VERSION}'/' Makefile
sed -r -i -e 's/^(QUILL_VERSION := ).*/\1'${QUILL_LATEST_VERSION}'/' Makefile
sed -r -i -e 's/^(GLOW_VERSION := ).*/\1'${GLOW_LATEST_VERSION}'/' Makefile
# export the versions for use with create-pull-request
@@ -51,7 +49,6 @@ jobs:
echo "GOSIMPORTS=$GOSIMPORTS_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "YAJSV=$YAJSV_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "COSIGN=$COSIGN_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "QUILL=$QUILL_LATEST_VERSION" >> $GITHUB_OUTPUT
echo "GLOW=GLOW_LATEST_VERSION" >> $GITHUB_OUTPUT
id: latest-versions
@@ -77,7 +74,6 @@ jobs:
- [gosimports ${{ steps.latest-versions.outputs.GOSIMPORTS }}](https://github.com/rinchsan/gosimports/releases/tag/${{ steps.latest-versions.outputs.GOSIMPORTS }})
- [yajsv ${{ steps.latest-versions.outputs.YAJSV }}](https://github.com/neilpa/yajsv/releases/tag/${{ steps.latest-versions.outputs.YAJSV }})
- [cosign ${{ steps.latest-versions.outputs.COSIGN }}](https://github.com/sigstore/cosign/releases/tag/${{ steps.latest-versions.outputs.COSIGN }})
- [quill ${{ steps.latest-versions.outputs.QUILL }}](https://github.com/anchore/quill/releases/tag/${{ steps.latest-versions.outputs.QUILL }})
- [glow ${{ steps.latest-versions.outputs.GLOW }}](https://github.com/charmbracelet/glow/releases/tag/${{ steps.latest-versions.outputs.GLOW }})
This is an auto-generated pull request to update all of the bootstrap tools to the latest versions.
token: ${{ steps.generate-token.outputs.token }}
+2 -2
View File
@@ -10,14 +10,14 @@ CHRONICLE_CMD = $(TEMP_DIR)/chronicle
GLOW_CMD = $(TEMP_DIR)/glow
# Tool versions #################################
GOLANGCILINT_VERSION := v1.54.2
GOLANGCILINT_VERSION := v1.54.1
GOSIMPORTS_VERSION := v0.3.8
BOUNCER_VERSION := v0.4.0
CHRONICLE_VERSION := v0.7.0
GORELEASER_VERSION := v1.20.0
YAJSV_VERSION := v1.4.1
COSIGN_VERSION := v2.1.1
QUILL_VERSION := v0.4.1
QUILL_VERSION := v0.2.0
GLOW_VERSION := v1.5.1
# Formatting variables #################################
@@ -27,7 +27,12 @@ report 1!!>
<notification 2>
<notification 3>
A newer version of syft is available for download: v0.33.0 (installed version is [not provided])
<my app can be updated!!
...to this version>
---
+1 -4
View File
@@ -10,7 +10,6 @@ import (
"github.com/wagoodman/go-partybus"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/version"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/parsers"
)
@@ -119,14 +118,12 @@ func writeAppUpdate(writer io.Writer, events ...partybus.Event) error {
style := lipgloss.NewStyle().Foreground(lipgloss.Color("13")).Italic(true)
for _, e := range events {
newVersion, err := parsers.ParseCLIAppUpdateAvailable(e)
notice, err := parsers.ParseCLIAppUpdateAvailable(e)
if err != nil {
log.WithFields("error", err).Warn("failed to parse app update notification")
continue
}
notice := fmt.Sprintf("A newer version of syft is available for download: %s (installed version is %s)", newVersion, version.FromBuild().Version)
if _, err := fmt.Fprintln(writer, style.Render(notice)); err != nil {
// don't let this be fatal
log.WithFields("error", err).Warn("failed to write app update notification")
@@ -35,7 +35,7 @@ func Test_postUIEventWriter_write(t *testing.T) {
},
{
Type: event.CLIAppUpdateAvailable,
Value: "v0.33.0",
Value: "\n\n<my app can be updated!!\n...to this version>\n\n",
},
{
Type: event.CLINotification,
+4 -6
View File
@@ -15,10 +15,10 @@ require (
github.com/facebookincubator/nvdtools v0.1.5
github.com/go-test/deep v1.1.0
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.1
github.com/google/uuid v1.3.0
github.com/gookit/color v1.5.4
github.com/hashicorp/go-multierror v1.1.1
github.com/jinzhu/copier v0.4.0
github.com/jinzhu/copier v0.3.5
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mholt/archiver/v3 v3.5.1
github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5
@@ -57,7 +57,7 @@ require (
github.com/anchore/stereoscope v0.0.0-20230727211946-d1f3d766295e
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
github.com/charmbracelet/bubbletea v0.24.2
github.com/charmbracelet/lipgloss v0.8.0
github.com/charmbracelet/lipgloss v0.7.1
github.com/dave/jennifer v1.7.0
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
github.com/docker/distribution v2.8.2+incompatible
@@ -69,11 +69,9 @@ require (
github.com/google/go-containerregistry v0.16.1
github.com/google/licensecheck v0.3.1
github.com/invopop/jsonschema v0.7.0
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
github.com/knqyf263/go-rpmdb v0.0.0-20230301153543-ba94b245509b
github.com/opencontainers/go-digest v1.0.0
github.com/saferwall/pe v1.4.4
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
github.com/sassoftware/go-rpmutils v0.2.0
github.com/vbatts/go-mtree v0.5.3
github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1
@@ -147,7 +145,7 @@ require (
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/muesli/termenv v0.15.1 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc3 // indirect
github.com/pborman/indent v1.2.1 // indirect
+8 -12
View File
@@ -147,8 +147,8 @@ github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
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.8.0 h1:IS00fk4XAHcf8uZKc3eHeMUTCxUH6NkaTrdyCQk84RU=
github.com/charmbracelet/lipgloss v0.8.0/go.mod h1:p4eYUZZJ/0oXTuCQKFF8mqyKCz0ja6y+7DniDDw5KKU=
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -355,8 +355,8 @@ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S3
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
@@ -419,8 +419,8 @@ github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy77
github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -428,8 +428,6 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 h1:WdAeg/imY2JFPc/9CST4bZ80nNJbiBFCAdSZCSgrS5Y=
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953/go.mod h1:6o+UrvuZWc4UTyBhQf0LGjW9Ld7qJxLz/OqvSOWWlEc=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
@@ -531,8 +529,8 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs=
github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
@@ -598,8 +596,6 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
github.com/saferwall/pe v1.4.4 h1:Ml++7/2/Z1iKwV4zCsd1nIqTEAdUQKAetwbbcCarhOg=
github.com/saferwall/pe v1.4.4/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/sassoftware/go-rpmutils v0.2.0 h1:pKW0HDYMFWQ5b4JQPiI3WI12hGsVoW0V8+GMoZiI/JE=
github.com/sassoftware/go-rpmutils v0.2.0/go.mod h1:TJJQYtLe/BeEmEjelI3b7xNZjzAukEkeWKmoakvaOoI=
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ=
+1 -1
View File
@@ -6,5 +6,5 @@ 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 = "10.0.1"
JSONSchemaVersion = "10.0.0"
)
File diff suppressed because it is too large Load Diff
+8 -26
View File
@@ -5,7 +5,6 @@ import (
"github.com/CycloneDX/cyclonedx-go"
"github.com/google/uuid"
"golang.org/x/exp/slices"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
@@ -140,7 +139,7 @@ func isExpressiblePackageRelationship(ty artifact.RelationshipType) bool {
}
func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependency {
dependencies := map[string]*cyclonedx.Dependency{}
result := make([]cyclonedx.Dependency, 0)
for _, r := range relationships {
exists := isExpressiblePackageRelationship(r.Type)
if !exists {
@@ -161,32 +160,15 @@ func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependenc
continue
}
toRef := deriveBomRef(toPkg)
dep := dependencies[toRef]
if dep == nil {
dep = &cyclonedx.Dependency{
Ref: toRef,
Dependencies: &[]string{},
}
dependencies[toRef] = dep
}
// ind dep
fromRef := deriveBomRef(fromPkg)
if !slices.Contains(*dep.Dependencies, fromRef) {
*dep.Dependencies = append(*dep.Dependencies, fromRef)
}
innerDeps := []string{}
innerDeps = append(innerDeps, deriveBomRef(fromPkg))
result = append(result, cyclonedx.Dependency{
Ref: deriveBomRef(toPkg),
Dependencies: &innerDeps,
})
}
result := make([]cyclonedx.Dependency, 0, len(dependencies))
for _, dep := range dependencies {
slices.Sort(*dep.Dependencies)
result = append(result, *dep)
}
slices.SortFunc(result, func(a, b cyclonedx.Dependency) bool {
return a.Ref < b.Ref
})
return result
}
@@ -1,7 +1,6 @@
package cyclonedxhelpers
import (
"fmt"
"testing"
"github.com/CycloneDX/cyclonedx-go"
@@ -44,34 +43,28 @@ func Test_relationships(t *testing.T) {
p1 := pkg.Package{
Name: "p1",
}
p1.SetID()
p2 := pkg.Package{
Name: "p2",
}
p2.SetID()
p3 := pkg.Package{
Name: "p3",
}
p4 := pkg.Package{
Name: "p4",
}
for _, p := range []*pkg.Package{&p1, &p2, &p3, &p4} {
p.PURL = fmt.Sprintf("pkg:generic/%s@%s", p.Name, p.Name)
p.SetID()
}
p3.SetID()
tests := []struct {
name string
sbom sbom.SBOM
expected *[]cyclonedx.Dependency
expected []string
}{
{
name: "package dependencyOf relationships output as dependencies",
sbom: sbom.SBOM{
Artifacts: sbom.Artifacts{
Packages: pkg.NewCollection(p1, p2, p3, p4),
Packages: pkg.NewCollection(p1, p2, p3),
},
Relationships: []artifact.Relationship{
{
@@ -84,28 +77,9 @@ func Test_relationships(t *testing.T) {
To: p1,
Type: artifact.DependencyOfRelationship,
},
{
From: p4,
To: p2,
Type: artifact.DependencyOfRelationship,
},
},
},
expected: &[]cyclonedx.Dependency{
{
Ref: deriveBomRef(p1),
Dependencies: &[]string{
deriveBomRef(p2),
deriveBomRef(p3),
},
},
{
Ref: deriveBomRef(p2),
Dependencies: &[]string{
deriveBomRef(p4),
},
},
},
expected: []string{p2.Name, p3.Name},
},
{
name: "package contains relationships not output",
@@ -134,7 +108,28 @@ func Test_relationships(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
cdx := ToFormatModel(test.sbom)
got := cdx.Dependencies
require.Equal(t, test.expected, got)
var deps []string
if got != nil {
for _, r := range *got {
for _, d := range *r.Dependencies {
c := findComponent(cdx, d)
require.NotNil(t, c)
deps = append(deps, c.Name)
}
}
}
require.Equal(t, test.expected, deps)
})
}
}
func findComponent(cdx *cyclonedx.BOM, bomRef string) *cyclonedx.Component {
for _, c := range *cdx.Components {
if c.BOMRef == bomRef {
return &c
}
}
return nil
}
@@ -349,13 +349,9 @@ func (r directoryIndexer) addSymlinkToIndex(p string, info os.FileInfo) (string,
}
if filepath.IsAbs(linkTarget) {
linkTarget = filepath.Clean(linkTarget)
// if the link is absolute (e.g, /bin/ls -> /bin/busybox) we need to
// resolve relative to the root of the base directory, if it is not already
// prefixed with a volume name
if filepath.VolumeName(linkTarget) == "" {
linkTarget = filepath.Join(r.base, filepath.Clean(linkTarget))
}
// resolve relative to the root of the base directory
linkTarget = filepath.Join(r.base, filepath.Clean(linkTarget))
} else {
// if the link is not absolute (e.g, /dev/stderr -> fd/2 ) we need to
// resolve it relative to the directory in question (e.g. resolve to
@@ -667,18 +667,6 @@ func Test_Cataloger_DefaultClassifiers_PositiveCases(t *testing.T) {
Metadata: metadata("nginx-binary"),
},
},
{
name: "positive-bash-5.2.15",
fixtureDir: "test-fixtures/classifiers/positive/bash-5.2.15",
expected: pkg.Package{
Name: "bash",
Version: "5.2.15",
Type: "binary",
PURL: "pkg:generic/bash@5.2.15",
Locations: locations("bash"),
Metadata: metadata("bash-binary"),
},
},
}
for _, test := range tests {
@@ -269,20 +269,6 @@ var defaultClassifiers = []classifier{
cpe.Must("cpe:2.3:a:nginx:nginx:*:*:*:*:*:*:*:*"),
},
},
{
Class: "bash-binary",
FileGlob: "**/bash",
EvidenceMatcher: fileContentsVersionMatcher(
// @(#)Bash version 5.2.15(1) release GNU
// @(#)Bash version 5.2.0(1) alpha GNU
// @(#)Bash version 5.2.0(1) beta GNU
// @(#)Bash version 5.2.0(1) rc4 GNU
`(?m)@\(#\)Bash version (?P<version>[0-9]+\.[0-9]+\.[0-9]+)\([0-9]\) [a-z0-9]+ GNU`,
),
Package: "bash",
PURL: mustPURL("pkg:generic/bash@version"),
CPEs: singleCPE("cpe:2.3:a:gnu:bash:*:*:*:*:*:*:*:*"),
},
}
// in both binaries and shared libraries, the version pattern is [NUL]3.11.2[NUL]
@@ -1 +0,0 @@
@(#)Bash version 5.2.15(1) release GNU
@@ -283,7 +283,6 @@
"360class.jansenhm": "cpe:2.3:a:360class.jansenhm_project:360class.jansenhm:*:*:*:*:*:node.js:*:*",
"626": "cpe:2.3:a:626_project:626:*:*:*:*:*:node.js:*:*",
"@actions/core": "cpe:2.3:a:toolkit_project:toolkit:*:*:*:*:*:node.js:*:*",
"@antfu/utils": "cpe:2.3:a:antfu:utils:*:*:*:*:*:node.js:*:*",
"@awsui/components-react": "cpe:2.3:a:amazon:awsui\\/components-react:*:*:*:*:*:node.js:*:*",
"@azure/ms-rest-nodeauth": "cpe:2.3:a:microsoft:ms-rest-nodeauth:*:*:*:*:*:node.js:*:*",
"@backstage/plugin-auth-backend": "cpe:2.3:a:linuxfoundation:auth_backend:*:*:*:*:*:node.js:*:*",
@@ -1082,7 +1081,6 @@
"spacy": "cpe:2.3:a:explosion:spacy:*:*:*:*:*:python:*:*",
"sqlparse": "cpe:2.3:a:sqlparse_project:sqlparse:*:*:*:*:*:python:*:*",
"tkvideoplayer": "cpe:2.3:a:python:tkvideoplayer:*:*:*:*:*:*:*:*",
"togglee": "cpe:2.3:a:togglee:togglee:*:*:*:*:*:pypi:*:*",
"urllib3": "cpe:2.3:a:python:urllib3:*:*:*:*:*:*:*:*",
"validators": "cpe:2.3:a:validators_project:validators:*:*:*:*:*:python:*:*",
"vault-cli": "cpe:2.3:a:vault-cli_project:vault-cli:*:*:*:*:*:python:*:*",
+18 -55
View File
@@ -5,7 +5,6 @@ import (
"github.com/scylladb/go-set/strset"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/syft/pkg"
)
@@ -13,24 +12,16 @@ var (
forbiddenProductGroupIDFields = strset.New("plugin", "plugins", "client")
forbiddenVendorGroupIDFields = strset.New("plugin", "plugins")
domains = []string{
"com",
"org",
"net",
"io",
"be",
}
PrimaryJavaManifestGroupIDFields = []string{
"Bundle-SymbolicName",
primaryJavaManifestGroupIDFields = []string{
"Extension-Name",
"Specification-Vendor",
"Implementation-Vendor",
"Bundle-SymbolicName",
"Implementation-Vendor-Id",
"Implementation-Title",
"Bundle-Activator",
}
SecondaryJavaManifestGroupIDFields = []string{
secondaryJavaManifestGroupIDFields = []string{
"Automatic-Module-Name",
"Main-Class",
"Package",
@@ -66,7 +57,7 @@ func vendorsFromJavaManifestNames(p pkg.Package) fieldCandidateSet {
for _, name := range javaManifestNameFields {
if metadata.Manifest.Main != nil {
if value, exists := metadata.Manifest.Main[name]; exists {
if !startsWithTopLevelDomain(value) {
if !looksLikeGroupID(value) {
vendors.add(fieldCandidate{
value: normalizePersonName(value),
disallowSubSelections: true,
@@ -80,7 +71,7 @@ func vendorsFromJavaManifestNames(p pkg.Package) fieldCandidateSet {
continue
}
if value, exists := section[name]; exists {
if !startsWithTopLevelDomain(value) {
if !looksLikeGroupID(value) {
vendors.add(fieldCandidate{
value: normalizePersonName(value),
disallowSubSelections: true,
@@ -144,7 +135,7 @@ func productsFromArtifactAndGroupIDs(artifactID string, groupIDs []string) []str
continue
}
// umbrella projects tend to have sub components that either start or end with the project name. We expect
// umbrella projects tend to have subcomponents that either start or end with the project name. We expect
// to identify fields that may represent the umbrella project, and not fields that indicate auxiliary
// information about the package.
couldBeProjectName := strings.HasPrefix(artifactID, field) || strings.HasSuffix(artifactID, field)
@@ -168,7 +159,7 @@ func artifactIDFromJavaPackage(p pkg.Package) string {
}
artifactID := strings.TrimSpace(metadata.PomProperties.ArtifactID)
if looksLikeGroupID(artifactID) && len(strings.Split(artifactID, ".")) > 1 {
if looksLikeGroupID(artifactID) {
// there is a strong indication that the artifact ID is really a group ID, don't use it
return ""
}
@@ -184,9 +175,6 @@ func GroupIDsFromJavaPackage(p pkg.Package) (groupIDs []string) {
return GroupIDsFromJavaMetadata(p.Name, metadata)
}
// GroupIDsFromJavaMetadata returns the possible group IDs for a Java package
// This function is similar to GroupIDFromJavaPackage, but returns all possible group IDs and is less strict
// It is used as a way to generate possible candidates for CPE matching.
func GroupIDsFromJavaMetadata(pkgName string, metadata pkg.JavaMetadata) (groupIDs []string) {
groupIDs = append(groupIDs, groupIDsFromPomProperties(metadata.PomProperties)...)
groupIDs = append(groupIDs, groupIDsFromPomProject(metadata.PomProject)...)
@@ -200,16 +188,10 @@ func groupIDsFromPomProperties(properties *pkg.PomProperties) (groupIDs []string
return nil
}
if startsWithTopLevelDomain(properties.GroupID) {
if properties.GroupID != "" {
groupIDs = append(groupIDs, cleanGroupID(properties.GroupID))
}
// sometimes the publisher puts the group ID in the artifact ID field unintentionally
if startsWithTopLevelDomain(properties.ArtifactID) && len(strings.Split(properties.ArtifactID, ".")) > 1 {
// there is a strong indication that the artifact ID is really a group ID
groupIDs = append(groupIDs, cleanGroupID(properties.ArtifactID))
}
return groupIDs
}
@@ -218,34 +200,19 @@ func groupIDsFromPomProject(project *pkg.PomProject) (groupIDs []string) {
return nil
}
// extract the project info...
groupIDs = addGroupIDsFromGroupIDsAndArtifactID(project.GroupID, project.ArtifactID)
if project.Parent == nil {
return groupIDs
if project.GroupID != "" {
groupIDs = append(groupIDs, project.GroupID)
}
// extract the parent project info...
groupIDs = append(groupIDs, addGroupIDsFromGroupIDsAndArtifactID(project.Parent.GroupID, project.Parent.ArtifactID)...)
return groupIDs
}
func addGroupIDsFromGroupIDsAndArtifactID(groupID, artifactID string) (groupIDs []string) {
if startsWithTopLevelDomain(groupID) {
groupIDs = append(groupIDs, cleanGroupID(groupID))
if project.Parent != nil && project.Parent.GroupID != "" {
groupIDs = append(groupIDs, project.Parent.GroupID)
}
// sometimes the publisher puts the group ID in the artifact ID field unintentionally
if startsWithTopLevelDomain(artifactID) && len(strings.Split(artifactID, ".")) > 1 {
// there is a strong indication that the artifact ID is really a group ID
groupIDs = append(groupIDs, cleanGroupID(artifactID))
}
return groupIDs
}
func groupIDsFromJavaManifest(pkgName string, manifest *pkg.JavaManifest) []string {
if groupID, ok := DefaultArtifactIDToGroupID[pkgName]; ok {
if groupID, ok := defaultArtifactIDToGroupID[pkgName]; ok {
return []string{groupID}
}
@@ -254,7 +221,7 @@ func groupIDsFromJavaManifest(pkgName string, manifest *pkg.JavaManifest) []stri
}
// try the common manifest fields first for a set of candidates
groupIDs := GetManifestFieldGroupIDs(manifest, PrimaryJavaManifestGroupIDFields)
groupIDs := getManifestFieldGroupIDs(manifest, primaryJavaManifestGroupIDFields)
if len(groupIDs) != 0 {
return groupIDs
@@ -265,23 +232,23 @@ func groupIDsFromJavaManifest(pkgName string, manifest *pkg.JavaManifest) []stri
// for more info see pkg:maven/commons-io/commons-io@2.8.0 within cloudbees/cloudbees-core-mm:2.263.4.2
// at /usr/share/jenkins/jenkins.war:WEB-INF/plugins/analysis-model-api.hpi:WEB-INF/lib/commons-io-2.8.0.jar
// as well as the ant package from cloudbees/cloudbees-core-mm:2.277.2.4-ra.
return GetManifestFieldGroupIDs(manifest, SecondaryJavaManifestGroupIDFields)
return getManifestFieldGroupIDs(manifest, secondaryJavaManifestGroupIDFields)
}
func GetManifestFieldGroupIDs(manifest *pkg.JavaManifest, fields []string) (groupIDs []string) {
func getManifestFieldGroupIDs(manifest *pkg.JavaManifest, fields []string) (groupIDs []string) {
if manifest == nil {
return nil
}
for _, name := range fields {
if value, exists := manifest.Main[name]; exists {
if startsWithTopLevelDomain(value) {
if looksLikeGroupID(value) {
groupIDs = append(groupIDs, cleanGroupID(value))
}
}
for _, section := range manifest.NamedSections {
if value, exists := section[name]; exists {
if startsWithTopLevelDomain(value) {
if looksLikeGroupID(value) {
groupIDs = append(groupIDs, cleanGroupID(value))
}
}
@@ -302,10 +269,6 @@ func removeOSCIDirectives(groupID string) string {
return strings.Split(groupID, ";")[0]
}
func startsWithTopLevelDomain(value string) bool {
return internal.HasAnyOfPrefixes(value, domains...)
}
func looksLikeGroupID(value string) bool {
return strings.Contains(value, ".")
}
@@ -1,6 +1,6 @@
package cpe
var DefaultArtifactIDToGroupID = map[string]string{
var defaultArtifactIDToGroupID = map[string]string{
"ant": "org.apache.ant",
"ant-antlr": "org.apache.ant",
"ant-antunit": "org.apache.ant",
+25 -70
View File
@@ -8,67 +8,23 @@ import (
"github.com/anchore/syft/syft/pkg"
)
type conanRef struct {
Name string
Version string
User string
Channel string
Revision string
Timestamp string
}
func splitConanRef(ref string) *conanRef {
// Conan ref format is:
// pkg/0.1@user/channel#rrev%timestamp
// This method is based on conan's ref.loads method:
// https://github.com/conan-io/conan/blob/release/2.0/conans/model/recipe_ref.py#L93C21-L93C21
var cref conanRef
// timestamp
tokens := strings.Split(ref, "%")
text := tokens[0]
if len(tokens) == 2 {
cref.Timestamp = tokens[1]
}
// revision
tokens = strings.Split(text, "#")
ref = tokens[0]
if len(tokens) == 2 {
cref.Revision = tokens[1]
}
// name and version are always given
tokens = strings.Split(ref, "@")
nameAndVersion := strings.Split(tokens[0], "/")
if len(nameAndVersion) < 2 || nameAndVersion[0] == "" || nameAndVersion[1] == "" {
func newConanfilePackage(m pkg.ConanMetadata, locations ...file.Location) *pkg.Package {
fields := strings.Split(strings.TrimSpace(m.Ref), "/")
if len(fields) < 2 {
return nil
}
cref.Name = nameAndVersion[0]
cref.Version = nameAndVersion[1]
// user and channel
if len(tokens) == 2 && tokens[1] != "" {
tokens = strings.Split(tokens[1], "/")
if len(tokens) == 2 {
cref.User = tokens[0]
cref.Channel = tokens[1]
}
}
return &cref
}
func newConanfilePackage(m pkg.ConanMetadata, locations ...file.Location) *pkg.Package {
ref := splitConanRef(m.Ref)
if ref == nil {
pkgName, pkgVersion := fields[0], fields[1]
if pkgName == "" || pkgVersion == "" {
return nil
}
p := pkg.Package{
Name: ref.Name,
Version: ref.Version,
Name: pkgName,
Version: pkgVersion,
Locations: file.NewLocationSet(locations...),
PURL: packageURL(ref),
PURL: packageURL(pkgName, pkgVersion),
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanMetadataType,
@@ -81,16 +37,22 @@ func newConanfilePackage(m pkg.ConanMetadata, locations ...file.Location) *pkg.P
}
func newConanlockPackage(m pkg.ConanLockMetadata, locations ...file.Location) *pkg.Package {
ref := splitConanRef(m.Ref)
if ref == nil {
fields := strings.Split(strings.Split(m.Ref, "@")[0], "/")
if len(fields) < 2 {
return nil
}
pkgName, pkgVersion := fields[0], fields[1]
if pkgName == "" || pkgVersion == "" {
return nil
}
p := pkg.Package{
Name: ref.Name,
Version: ref.Version,
Name: pkgName,
Version: pkgVersion,
Locations: file.NewLocationSet(locations...),
PURL: packageURL(ref),
PURL: packageURL(pkgName, pkgVersion),
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanLockMetadataType,
@@ -102,20 +64,13 @@ func newConanlockPackage(m pkg.ConanLockMetadata, locations ...file.Location) *p
return &p
}
func packageURL(ref *conanRef) string {
qualifiers := packageurl.Qualifiers{}
if ref.Channel != "" {
qualifiers = append(qualifiers, packageurl.Qualifier{
Key: "channel",
Value: ref.Channel,
})
}
func packageURL(name, version string) string {
return packageurl.NewPackageURL(
packageurl.TypeConan,
ref.User,
ref.Name,
ref.Version,
qualifiers,
"",
name,
version,
nil, // TODO: no qualifiers (...yet)
"",
).ToString()
}
+1 -1
View File
@@ -36,7 +36,7 @@ func parseConanfile(_ file.Resolver, _ *generic.Environment, reader file.Locatio
switch {
case strings.Contains(line, "[requires]"):
inRequirements = true
case strings.ContainsAny(line, "[]") || strings.HasPrefix(strings.TrimSpace(line), "#"):
case strings.ContainsAny(line, "[]#"):
inRequirements = false
}
@@ -52,13 +52,13 @@ func TestParseConanfile(t *testing.T) {
{
Name: "spdlog",
Version: "1.9.2",
PURL: "pkg:conan/my_user/spdlog@1.9.2?channel=my_channel",
PURL: "pkg:conan/spdlog@1.9.2",
Locations: fixtureLocationSet,
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanMetadataType,
Metadata: pkg.ConanMetadata{
Ref: "spdlog/1.9.2@my_user/my_channel#1234567%%987654",
Ref: "spdlog/1.9.2",
},
},
{
@@ -70,19 +70,19 @@ func TestParseConanfile(t *testing.T) {
Type: pkg.ConanPkg,
MetadataType: pkg.ConanMetadataType,
Metadata: pkg.ConanMetadata{
Ref: "sdl/2.0.20#1234567%%987654",
Ref: "sdl/2.0.20",
},
},
{
Name: "fltk",
Version: "1.3.8",
PURL: "pkg:conan/my_user/fltk@1.3.8?channel=my_channel",
PURL: "pkg:conan/fltk@1.3.8",
Locations: fixtureLocationSet,
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanMetadataType,
Metadata: pkg.ConanMetadata{
Ref: "fltk/1.3.8@my_user/my_channel",
Ref: "fltk/1.3.8",
},
},
}
+7 -36
View File
@@ -13,49 +13,20 @@ func TestParseConanlock(t *testing.T) {
fixture := "test-fixtures/conan.lock"
expected := []pkg.Package{
{
Name: "spdlog",
Version: "1.11.0",
PURL: "pkg:conan/spdlog@1.11.0",
Name: "zlib",
Version: "1.2.12",
PURL: "pkg:conan/zlib@1.2.12",
Locations: file.NewLocationSet(file.NewLocation(fixture)),
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanLockMetadataType,
Metadata: pkg.ConanLockMetadata{
Ref: "spdlog/1.11.0",
Ref: "zlib/1.2.12",
Options: map[string]string{
"fPIC": "True",
"header_only": "False",
"no_exceptions": "False",
"shared": "False",
"wchar_filenames": "False",
"wchar_support": "False",
"fmt:fPIC": "True",
"fmt:header_only": "False",
"fmt:shared": "False",
"fmt:with_fmt_alias": "False",
"fmt:with_os_api": "True",
},
Path: "conanfile.py",
Context: "host",
},
},
{
Name: "fmt",
Version: "9.1.0",
PURL: "pkg:conan/my_user/fmt@9.1.0?channel=my_channel",
Locations: file.NewLocationSet(file.NewLocation(fixture)),
Language: pkg.CPP,
Type: pkg.ConanPkg,
MetadataType: pkg.ConanLockMetadataType,
Metadata: pkg.ConanLockMetadata{
Ref: "fmt/9.1.0@my_user/my_channel#6708c9d84f98d56a6d9f2e6c2d5639ba",
Options: map[string]string{
"fPIC": "True",
"header_only": "False",
"shared": "False",
"with_fmt_alias": "False",
"with_os_api": "True",
"fPIC": "True",
"shared": "False",
},
Path: "all/conanfile.py",
Context: "host",
},
},
@@ -2,24 +2,15 @@
"graph_lock": {
"nodes": {
"0": {
"ref": "spdlog/1.11.0",
"options": "fPIC=True\nheader_only=False\nno_exceptions=False\nshared=False\nwchar_filenames=False\nwchar_support=False\nfmt:fPIC=True\nfmt:header_only=False\nfmt:shared=False\nfmt:with_fmt_alias=False\nfmt:with_os_api=True",
"requires": [
"1"
],
"path": "conanfile.py",
"context": "host"
},
"1": {
"ref": "fmt/9.1.0@my_user/my_channel#6708c9d84f98d56a6d9f2e6c2d5639ba",
"options": "fPIC=True\nheader_only=False\nshared=False\nwith_fmt_alias=False\nwith_os_api=True",
"package_id": "2c09c8f84c016041549fcee94e4caae5d89424b6",
"prev": "9f5ab13fc7c73e4a9f87e4e213f2cfa4",
"ref": "zlib/1.2.12",
"options": "fPIC=True\nshared=False",
"requires": [],
"path": "all/conanfile.py",
"context": "host"
}
},
"revisions_enabled": true
"revisions_enabled": false
},
"version": "0.4",
"profile_host": "[settings]\narch=x86_64\narch.march=None\narch_build=x86_64\nbuild_type=Release\ncompiler=gcc\ncompiler.libcxx=libstdc++11\ncompiler.version=11\nos=Linux\nos_build=Linux\n[options]\n[build_requires]\n[env]\n"
}
"profile_host": "[settings]\narch=x86_64\narch_build=x86_64\nbuild_type=Release\ncompiler=gcc\ncompiler.libcxx=libstdc++\ncompiler.version=9\nos=Linux\nos_build=Linux\n[options]\n[build_requires]\n[env]\n"
}
@@ -4,9 +4,9 @@
catch2/2.13.8
docopt.cpp/0.6.3
fmt/8.1.1
spdlog/1.9.2@my_user/my_channel#1234567%%987654
sdl/2.0.20#1234567%%987654
fltk/1.3.8@my_user/my_channel
spdlog/1.9.2
sdl/2.0.20
fltk/1.3.8
[generators]
cmake_find_package_multi
+1 -2
View File
@@ -11,7 +11,7 @@ import (
"github.com/anchore/syft/syft/pkg"
)
func (c *goBinaryCataloger) newGoBinaryPackage(resolver file.Resolver, dep *debug.Module, mainModule, goVersion, architecture string, buildSettings map[string]string, cryptoSettings []string, locations ...file.Location) pkg.Package {
func (c *goBinaryCataloger) newGoBinaryPackage(resolver file.Resolver, dep *debug.Module, mainModule, goVersion, architecture string, buildSettings map[string]string, locations ...file.Location) pkg.Package {
if dep.Replace != nil {
dep = dep.Replace
}
@@ -36,7 +36,6 @@ func (c *goBinaryCataloger) newGoBinaryPackage(resolver file.Resolver, dep *debu
Architecture: architecture,
BuildSettings: buildSettings,
MainModule: mainModule,
GoCryptoSettings: cryptoSettings,
},
}
+3 -5
View File
@@ -66,7 +66,7 @@ func (c *goBinaryCataloger) parseGoBinary(resolver file.Resolver, _ *generic.Env
return pkgs, nil, nil
}
func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *extendedBuildInfo, arch string, location file.Location) pkg.Package {
func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *debug.BuildInfo, arch string, location file.Location) pkg.Package {
gbs := getBuildSettings(mod.Settings)
main := c.newGoBinaryPackage(
resolver,
@@ -75,7 +75,6 @@ func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *exten
mod.GoVersion,
arch,
gbs,
mod.cryptoSettings,
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
)
@@ -154,7 +153,7 @@ func extractVersionFromLDFlags(ldflags string) (majorVersion string, fullVersion
// getArchs finds a binary architecture by two ways:
// 1) reading build info from binaries compiled by go1.18+
// 2) reading file headers from binaries compiled by < go1.18
func getArchs(readers []io.ReaderAt, builds []*extendedBuildInfo) []string {
func getArchs(readers []io.ReaderAt, builds []*debug.BuildInfo) []string {
if len(readers) != len(builds) {
log.Trace("golang cataloger: bin parsing: number of builds and readers doesn't match")
return nil
@@ -256,7 +255,7 @@ func createMainModuleFromPath(path string) (mod debug.Module) {
return
}
func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file.Location, mod *extendedBuildInfo, arch string) []pkg.Package {
func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file.Location, mod *debug.BuildInfo, arch string) []pkg.Package {
var pkgs []pkg.Package
if mod == nil {
return pkgs
@@ -278,7 +277,6 @@ func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file
mod.GoVersion,
arch,
nil,
mod.cryptoSettings,
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
)
if pkg.IsValid(&p) {
+139 -164
View File
@@ -155,7 +155,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
tests := []struct {
name string
mod *extendedBuildInfo
mod *debug.BuildInfo
arch string
expected []pkg.Package
}{
@@ -166,18 +166,16 @@ func TestBuildGoPkgInfo(t *testing.T) {
},
{
name: "package without name",
mod: &extendedBuildInfo{
&debug.BuildInfo{
Deps: []*debug.Module{
{
Path: "github.com/adrg/xdg",
},
{
Path: "",
Version: "v0.2.1",
},
mod: &debug.BuildInfo{
Deps: []*debug.Module{
{
Path: "github.com/adrg/xdg",
},
}, nil,
{
Path: "",
Version: "v0.2.1",
},
},
},
expected: []pkg.Package{
{
@@ -200,28 +198,26 @@ func TestBuildGoPkgInfo(t *testing.T) {
},
{
name: "buildGoPkgInfo parses a blank mod and returns no packages",
mod: &extendedBuildInfo{&debug.BuildInfo{}, nil},
mod: &debug.BuildInfo{},
expected: []pkg.Package(nil),
},
{
name: "parse a mod without main module",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
},
Deps: []*debug.Module{
{
Path: "github.com/adrg/xdg",
Version: "v0.2.1",
Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=",
},
Deps: []*debug.Module{
{
Path: "github.com/adrg/xdg",
Version: "v0.2.1",
Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=",
},
},
}, nil,
},
},
expected: []pkg.Package{
{
@@ -250,16 +246,14 @@ func TestBuildGoPkgInfo(t *testing.T) {
{
name: "parse a mod with path but no main module",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
},
Path: "github.com/a/b/c",
}, []string{"boringcrypto + fips"},
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
},
Path: "github.com/a/b/c",
},
expected: []pkg.Package{
{
@@ -286,8 +280,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
"GOARCH": "amd64",
"GOOS": "darwin",
},
MainModule: "github.com/a/b/c",
GoCryptoSettings: []string{"boringcrypto + fips"},
MainModule: "github.com/a/b/c",
},
},
},
@@ -295,35 +288,31 @@ func TestBuildGoPkgInfo(t *testing.T) {
{
name: "parse a mod without packages",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
},
}, nil,
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
},
},
expected: []pkg.Package{unmodifiedMain},
},
{
name: "parse main mod and replace devel pseudo version and ldflags exists (but contains no version)",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"},
{Key: "vcs.time", Value: "2022-10-14T19:54:57Z"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`},
},
}, nil,
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"},
{Key: "vcs.time", Value: "2022-10-14T19:54:57Z"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`},
},
},
expected: []pkg.Package{
{
@@ -360,19 +349,17 @@ func TestBuildGoPkgInfo(t *testing.T) {
{
name: "parse main mod and replace devel version with one from ldflags with vcs. build settings",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"},
{Key: "vcs.time", Value: "2022-10-14T19:54:57Z"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`},
},
}, nil,
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"},
{Key: "vcs.time", Value: "2022-10-14T19:54:57Z"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`},
},
},
expected: []pkg.Package{
{
@@ -409,17 +396,15 @@ func TestBuildGoPkgInfo(t *testing.T) {
{
name: "parse main mod and replace devel version with one from ldflags without any vcs. build settings",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`},
},
}, nil,
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`},
},
},
expected: []pkg.Package{
{
@@ -454,17 +439,15 @@ func TestBuildGoPkgInfo(t *testing.T) {
{
name: "parse main mod and replace devel version with one from ldflags main.version without any vcs. build settings",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`},
},
}, nil,
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`},
},
},
expected: []pkg.Package{
{
@@ -499,17 +482,15 @@ func TestBuildGoPkgInfo(t *testing.T) {
{
name: "parse main mod and replace devel version with one from ldflags main.Version without any vcs. build settings",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`},
},
}, nil,
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`},
},
},
expected: []pkg.Package{
{
@@ -544,18 +525,16 @@ func TestBuildGoPkgInfo(t *testing.T) {
{
name: "parse main mod and replace devel version with a pseudo version",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"},
{Key: "vcs.time", Value: "2022-10-14T19:54:57Z"},
},
}, nil,
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
{Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"},
{Key: "vcs.time", Value: "2022-10-14T19:54:57Z"},
},
},
expected: []pkg.Package{
{
@@ -591,28 +570,26 @@ func TestBuildGoPkgInfo(t *testing.T) {
{
name: "parse a populated mod string and returns packages but no source info",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
},
Deps: []*debug.Module{
{
Path: "github.com/adrg/xdg",
Version: "v0.2.1",
Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=",
},
Deps: []*debug.Module{
{
Path: "github.com/adrg/xdg",
Version: "v0.2.1",
Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=",
},
{
Path: "github.com/anchore/client-go",
Version: "v0.0.0-20210222170800-9c70f9b80bcf",
Sum: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=",
},
{
Path: "github.com/anchore/client-go",
Version: "v0.0.0-20210222170800-9c70f9b80bcf",
Sum: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=",
},
}, nil,
},
},
expected: []pkg.Package{
{
@@ -665,33 +642,31 @@ func TestBuildGoPkgInfo(t *testing.T) {
{
name: "parse a populated mod string and returns packages when a replace directive exists",
arch: archDetails,
mod: &extendedBuildInfo{
&debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
mod: &debug.BuildInfo{
GoVersion: goCompiledVersion,
Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"},
Settings: []debug.BuildSetting{
{Key: "GOARCH", Value: archDetails},
{Key: "GOOS", Value: "darwin"},
{Key: "GOAMD64", Value: "v1"},
},
Deps: []*debug.Module{
{
Path: "golang.org/x/sys",
Version: "v0.0.0-20211006194710-c8a6f5223071",
Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=",
},
Deps: []*debug.Module{
{
Path: "golang.org/x/sys",
Version: "v0.0.0-20211006194710-c8a6f5223071",
Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=",
},
{
{
Path: "golang.org/x/term",
Version: "v0.0.0-20210927222741-03fcf44c2211",
Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=",
Replace: &debug.Module{
Path: "golang.org/x/term",
Version: "v0.0.0-20210927222741-03fcf44c2211",
Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=",
Replace: &debug.Module{
Path: "golang.org/x/term",
Version: "v0.0.0-20210916214954-140adaaadfaf",
Sum: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=",
},
Version: "v0.0.0-20210916214954-140adaaadfaf",
Sum: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=",
},
},
}, nil,
},
},
expected: []pkg.Package{
{
+3 -40
View File
@@ -6,19 +6,12 @@ import (
"io"
"runtime/debug"
"github.com/kastenhq/goversion/version"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
)
type extendedBuildInfo struct {
*debug.BuildInfo
cryptoSettings []string
}
// scanFile scans file to try to report the Go and module versions.
func scanFile(reader unionreader.UnionReader, filename string) ([]*extendedBuildInfo, []string) {
func scanFile(reader unionreader.UnionReader, filename string) ([]*debug.BuildInfo, []string) {
// NOTE: multiple readers are returned to cover universal binaries, which are files
// with more than one binary
readers, err := unionreader.GetReaders(reader)
@@ -27,7 +20,7 @@ func scanFile(reader unionreader.UnionReader, filename string) ([]*extendedBuild
return nil, nil
}
var builds []*extendedBuildInfo
var builds []*debug.BuildInfo
for _, r := range readers {
bi, err := getBuildInfo(r)
if err != nil {
@@ -37,14 +30,7 @@ func scanFile(reader unionreader.UnionReader, filename string) ([]*extendedBuild
if bi == nil {
continue
}
v, err := getCryptoInformation(r)
if err != nil {
log.WithFields("file", filename, "error", err).Trace("unable to read golang version info")
continue
}
builds = append(builds, &extendedBuildInfo{bi, v})
builds = append(builds, bi)
}
archs := getArchs(readers, builds)
@@ -52,29 +38,6 @@ func scanFile(reader unionreader.UnionReader, filename string) ([]*extendedBuild
return builds, archs
}
func getCryptoInformation(reader io.ReaderAt) ([]string, error) {
v, err := version.ReadExeFromReader(reader)
if err != nil {
return nil, err
}
return getCryptoSettingsFromVersion(v), nil
}
func getCryptoSettingsFromVersion(v version.Version) []string {
cryptoSettings := []string{}
if v.StandardCrypto {
cryptoSettings = append(cryptoSettings, "standard-crypto")
}
if v.BoringCrypto {
cryptoSettings = append(cryptoSettings, "boring-crypto")
}
if v.FIPSOnly {
cryptoSettings = append(cryptoSettings, "crypto/tls/fipsonly")
}
return cryptoSettings
}
func getBuildInfo(r io.ReaderAt) (bi *debug.BuildInfo, err error) {
defer func() {
if r := recover(); r != nil {
@@ -6,7 +6,6 @@ import (
"runtime/debug"
"testing"
"github.com/kastenhq/goversion/version"
"github.com/stretchr/testify/assert"
)
@@ -39,72 +38,3 @@ func Test_getBuildInfo(t *testing.T) {
})
}
}
func Test_getCryptoSettingsFromVersion(t *testing.T) {
for _, tt := range []struct {
name string
version version.Version
result []string
}{
{
name: "standard crypto",
version: version.Version{
StandardCrypto: true,
},
result: []string{"standard-crypto"},
},
{
name: "boring crypto",
version: version.Version{
BoringCrypto: true,
},
result: []string{"boring-crypto"},
},
{ // Should never see this. Boring crypto is required for fipsonly
name: "fipsonly",
version: version.Version{
FIPSOnly: true,
},
result: []string{"crypto/tls/fipsonly"},
},
{
name: "boring crypto and fipsonly",
version: version.Version{
BoringCrypto: true,
FIPSOnly: true,
},
result: []string{"boring-crypto", "crypto/tls/fipsonly"},
},
{ // Should never see this.
name: "boring and standard crypto!",
version: version.Version{
BoringCrypto: true,
StandardCrypto: true,
},
result: []string{"boring-crypto", "standard-crypto"},
},
{ // Should never see this. Boring crypto is required for fipsonly
name: "fipsonly and standard crypto!",
version: version.Version{
FIPSOnly: true,
StandardCrypto: true,
},
result: []string{"crypto/tls/fipsonly", "standard-crypto"},
},
{ // Should never see this. Boring crypto is required for fipsonly
name: "fipsonly boringcrypto and standard crypto!",
version: version.Version{
FIPSOnly: true,
StandardCrypto: true,
BoringCrypto: true,
},
result: []string{"crypto/tls/fipsonly", "standard-crypto", "boring-crypto"},
},
} {
t.Run(tt.name, func(t *testing.T) {
res := getCryptoSettingsFromVersion(tt.version)
assert.ElementsMatch(t, res, tt.result)
})
}
}
+21 -44
View File
@@ -62,11 +62,11 @@ func parseJavaArchive(_ file.Resolver, _ *generic.Environment, reader file.Locat
}
// uniquePkgKey creates a unique string to identify the given package.
func uniquePkgKey(groupID string, p *pkg.Package) string {
func uniquePkgKey(p *pkg.Package) string {
if p == nil {
return ""
}
return fmt.Sprintf("%s|%s|%s", groupID, p.Name, p.Version)
return fmt.Sprintf("%s|%s", p.Name, p.Version)
}
// newJavaArchiveParser returns a new java archive parser object for the given archive. Can be configured to discover
@@ -371,27 +371,13 @@ func pomProjectByParentPath(archivePath string, location file.Location, extractP
return projectByParentPath, nil
}
// newPackageFromMavenData processes a single Maven POM properties for a given parent package, returning all listed Java packages found and
// packagesFromPomProperties processes a single Maven POM properties for a given parent package, returning all listed Java packages found and
// associating each discovered package to the given parent package. Note the pom.xml is optional, the pom.properties is not.
func newPackageFromMavenData(pomProperties pkg.PomProperties, pomProject *pkg.PomProject, parentPkg *pkg.Package, location file.Location) *pkg.Package {
// keep the artifact name within the virtual path if this package does not match the parent package
vPathSuffix := ""
groupID := ""
if parentMetadata, ok := parentPkg.Metadata.(pkg.JavaMetadata); ok {
groupID = groupIDFromJavaMetadata(parentPkg.Name, parentMetadata)
}
parentKey := fmt.Sprintf("%s:%s:%s", groupID, parentPkg.Name, parentPkg.Version)
// Since we don't have a package yet, it's important to use the same `field: value` association that we used when creating the parent package
// See below where Name => pomProperties.ArtifactID and Version => pomProperties.Version. We want to check for potentially nested identical
// packages and create equal virtual paths so they are de duped in the future
pomProjectKey := fmt.Sprintf("%s:%s:%s", pomProperties.GroupID, pomProperties.ArtifactID, pomProperties.Version)
if parentKey != pomProjectKey {
// build a new virtual path suffix for the package that is different from the parent package
// we want to use the GroupID and ArtifactID here to preserve uniqueness
// Some packages have the same name but different group IDs (e.g. "org.glassfish.jaxb/jaxb-core", "com.sun.xml.bind/jaxb-core")
// https://github.com/anchore/syft/issues/1944
vPathSuffix += ":" + pomProperties.GroupID + ":" + pomProperties.ArtifactID
if !strings.HasPrefix(pomProperties.ArtifactID, parentPkg.Name) {
vPathSuffix += ":" + pomProperties.ArtifactID
}
virtualPath := location.AccessPath() + vPathSuffix
@@ -422,26 +408,21 @@ func newPackageFromMavenData(pomProperties pkg.PomProperties, pomProject *pkg.Po
}
func packageIdentitiesMatch(p pkg.Package, parentPkg *pkg.Package) bool {
metadata, ok := p.Metadata.(pkg.JavaMetadata)
parentMetadata, parentOk := parentPkg.Metadata.(pkg.JavaMetadata)
if !ok || !parentOk {
switch {
case !ok:
log.WithFields("package", p.String()).Trace("unable to extract java metadata to check for matching package identity for package: %s", p.Name)
case !parentOk:
log.WithFields("package", parentPkg.String()).Trace("unable to extract java metadata to check for matching package identity for package: %s", parentPkg.Name)
}
// if we can't extract metadata, we can check for matching identities via the package name
// this is not ideal, but it's better than nothing - this should not be used if we have Metadata
return uniquePkgKey("", &p) == uniquePkgKey("", parentPkg)
// the name/version pair matches...
if uniquePkgKey(&p) == uniquePkgKey(parentPkg) {
return true
}
// try to determine identity with the metadata
groupID := groupIDFromJavaMetadata(p.Name, metadata)
parentGroupID := groupIDFromJavaMetadata(parentPkg.Name, parentMetadata)
if uniquePkgKey(groupID, &p) == uniquePkgKey(parentGroupID, parentPkg) {
return true
metadata, ok := p.Metadata.(pkg.JavaMetadata)
if !ok {
log.WithFields("package", p.String()).Warn("unable to extract java metadata to check for matching package identity")
return false
}
parentMetadata, ok := parentPkg.Metadata.(pkg.JavaMetadata)
if !ok {
log.WithFields("package", p.String()).Warn("unable to extract java metadata from parent for verifying virtual path")
return false
}
// the virtual path matches...
@@ -453,14 +434,10 @@ func packageIdentitiesMatch(p pkg.Package, parentPkg *pkg.Package) bool {
// note: you CANNOT use name-is-subset-of-artifact-id or vice versa --this is too generic. Shaded jars are a good
// example of this: where the package name is "cloudbees-analytics-segment-driver" and a child is "analytics", but
// they do not indicate the same package.
// NOTE: artifactId might not be a good indicator of uniqueness since archives can contain forks with the same name
// from different groups (e.g. "org.glassfish.jaxb.jaxb-core" and "com.sun.xml.bind.jaxb-core")
// we will use this check as a last resort
if metadata.PomProperties != nil {
if metadata.PomProperties.ArtifactID != "" && parentPkg.Name == metadata.PomProperties.ArtifactID {
return true
}
if metadata.PomProperties.ArtifactID != "" && parentPkg.Name == metadata.PomProperties.ArtifactID {
return true
}
return false
}
+44 -6
View File
@@ -174,8 +174,8 @@ func TestParseJar(t *testing.T) {
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
// ensure that nested packages with different names than that of the parent are appended as
// a suffix on the virtual path with a colon separator between group name and artifact name
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar:joda-time:joda-time",
// a suffix on the virtual path
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar:joda-time",
PomProperties: &pkg.PomProperties{
Path: "META-INF/maven/joda-time/joda-time/pom.properties",
GroupID: "joda-time",
@@ -240,7 +240,7 @@ func TestParseJar(t *testing.T) {
Metadata: pkg.JavaMetadata{
// ensure that nested packages with different names than that of the parent are appended as
// a suffix on the virtual path
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar:joda-time:joda-time",
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar:joda-time",
PomProperties: &pkg.PomProperties{
Path: "META-INF/maven/joda-time/joda-time/pom.properties",
GroupID: "joda-time",
@@ -659,7 +659,7 @@ func Test_newPackageFromMavenData(t *testing.T) {
Type: pkg.JavaPkg,
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":" + "some-group-id" + ":" + "some-artifact-id",
VirtualPath: virtualPath + ":" + "some-artifact-id",
PomProperties: &pkg.PomProperties{
Name: "some-name",
GroupID: "some-group-id",
@@ -728,7 +728,7 @@ func Test_newPackageFromMavenData(t *testing.T) {
Type: pkg.JavaPkg,
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":" + "some-group-id" + ":" + "some-artifact-id",
VirtualPath: virtualPath + ":" + "some-artifact-id",
PomProperties: &pkg.PomProperties{
Name: "some-name",
GroupID: "some-group-id",
@@ -797,7 +797,7 @@ func Test_newPackageFromMavenData(t *testing.T) {
Type: pkg.JenkinsPluginPkg,
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":" + "com.cloudbees.jenkins.plugins" + ":" + "some-artifact-id",
VirtualPath: virtualPath + ":" + "some-artifact-id",
PomProperties: &pkg.PomProperties{
Name: "some-name",
GroupID: "com.cloudbees.jenkins.plugins",
@@ -894,6 +894,44 @@ func Test_newPackageFromMavenData(t *testing.T) {
},
expectedPackage: nil,
},
{
name: "child matches parent by virtual path -- override name and version",
props: pkg.PomProperties{
Name: "some-name",
GroupID: "some-group-id",
ArtifactID: "some-parent-name", // note: DOES NOT match parent package
Version: "3.0", // note: DOES NOT match parent package
},
parent: &pkg.Package{
Name: "", // note: empty, so should not be matched on
Version: "", // note: empty, so should not be matched on
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath, // note: matching virtual path
Manifest: nil,
PomProperties: nil,
Parent: nil,
},
},
expectedParent: pkg.Package{
Name: "some-parent-name",
Version: "3.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath,
Manifest: nil,
// note: we attach the discovered pom properties data
PomProperties: &pkg.PomProperties{
Name: "some-name",
GroupID: "some-group-id",
ArtifactID: "some-parent-name",
Version: "3.0",
},
Parent: nil,
},
},
expectedPackage: nil,
},
{
name: "child matches parent by artifact id",
props: pkg.PomProperties{
+3 -123
View File
@@ -1,8 +1,6 @@
package java
import (
"strings"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/common/cpe"
@@ -11,9 +9,9 @@ import (
// PackageURL returns the PURL for the specific java package (see https://github.com/package-url/purl-spec)
func packageURL(name, version string, metadata pkg.JavaMetadata) string {
var groupID = name
if gID := groupIDFromJavaMetadata(name, metadata); gID != "" {
groupID = gID
groupIDs := cpe.GroupIDsFromJavaMetadata(name, metadata)
if len(groupIDs) > 0 {
groupID = groupIDs[0]
}
pURL := packageurl.NewPackageURL(
@@ -25,121 +23,3 @@ func packageURL(name, version string, metadata pkg.JavaMetadata) string {
"")
return pURL.ToString()
}
// GroupIDFromJavaPackage returns the authoritative group ID for a Java package.
// The order of precedence is:
// 1. The group ID from the POM properties
// 2. The group ID from the POM project
// 3. The group ID from a select map of known group IDs
// 4. The group ID from the Java manifest
func groupIDFromJavaMetadata(pkgName string, metadata pkg.JavaMetadata) (groupID string) {
if groupID = groupIDFromPomProperties(metadata.PomProperties); groupID != "" {
return groupID
}
if groupID = groupIDFromPomProject(metadata.PomProject); groupID != "" {
return groupID
}
if groupID = groupIDFromKnownPackageList(pkgName); groupID != "" {
return groupID
}
if groupID = groupIDFromJavaManifest(metadata.Manifest); groupID != "" {
return groupID
}
return groupID
}
func groupIDFromKnownPackageList(pkgName string) (groupID string) {
if groupID, ok := cpe.DefaultArtifactIDToGroupID[pkgName]; ok {
return groupID
}
return groupID
}
func groupIDFromJavaManifest(manifest *pkg.JavaManifest) (groupID string) {
if manifest == nil {
return groupID
}
groupIDS := cpe.GetManifestFieldGroupIDs(manifest, cpe.PrimaryJavaManifestGroupIDFields)
// assumes that primaryJavaManifestNameFields are ordered by priority
if len(groupIDS) != 0 {
return groupIDS[0]
}
groupIDS = cpe.GetManifestFieldGroupIDs(manifest, cpe.SecondaryJavaManifestGroupIDFields)
if len(groupIDS) != 0 {
return groupIDS[0]
}
return groupID
}
func groupIDFromPomProperties(properties *pkg.PomProperties) (groupID string) {
if properties == nil {
return groupID
}
if properties.GroupID != "" {
return cleanGroupID(properties.GroupID)
}
// sometimes the publisher puts the group ID in the artifact ID field unintentionally
if looksLikeGroupID(properties.ArtifactID) {
// there is a strong indication that the artifact ID is really a group ID
return cleanGroupID(properties.ArtifactID)
}
return groupID
}
func groupIDFromPomProject(project *pkg.PomProject) (groupID string) {
if project == nil {
return groupID
}
// check the project details
if project.GroupID != "" {
return cleanGroupID(project.GroupID)
}
// sometimes the publisher puts the group ID in the artifact ID field unintentionally
if looksLikeGroupID(project.ArtifactID) {
// there is a strong indication that the artifact ID is really a group ID
return cleanGroupID(project.ArtifactID)
}
// let's check the parent details
// if the current project does not have a group ID, but the parent does, we'll use the parent's group ID
if project.Parent != nil {
if project.Parent.GroupID != "" {
return cleanGroupID(project.Parent.GroupID)
}
// sometimes the publisher puts the group ID in the artifact ID field unintentionally
if looksLikeGroupID(project.Parent.ArtifactID) {
// there is a strong indication that the artifact ID is really a group ID
return cleanGroupID(project.Parent.ArtifactID)
}
}
return groupID
}
func looksLikeGroupID(value string) bool {
return strings.Contains(value, ".")
}
func cleanGroupID(groupID string) string {
return strings.TrimSpace(removeOSCIDirectives(groupID))
}
func removeOSCIDirectives(groupID string) string {
// for example:
// org.bar;uses:=“org.foo” -> org.bar
// more about OSGI directives see https://spring.io/blog/2008/10/20/understanding-the-osgi-uses-directive/
return strings.Split(groupID, ";")[0]
}
-142
View File
@@ -10,12 +10,10 @@ import (
func Test_packageURL(t *testing.T) {
tests := []struct {
name string
pkg pkg.Package
expect string
}{
{
name: "maven",
pkg: pkg.Package{
Name: "example-java-app-maven",
Version: "0.1.0",
@@ -40,90 +38,6 @@ func Test_packageURL(t *testing.T) {
},
expect: "pkg:maven/org.anchore/example-java-app-maven@0.1.0",
},
{
name: "POM properties have explicit group ID without . in it",
pkg: pkg.Package{
Name: "example-java-app-maven",
Version: "0.1.0",
Language: pkg.Java,
Type: pkg.JavaPkg,
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
Manifest: &pkg.JavaManifest{
Main: map[string]string{
"Manifest-Version": "1.0",
},
},
PomProperties: &pkg.PomProperties{
Path: "META-INF/maven/org.anchore/example-java-app-maven/pom.properties",
GroupID: "commons",
ArtifactID: "example-java-app-maven",
Version: "0.1.0",
Extra: make(map[string]string),
},
},
},
expect: "pkg:maven/commons/example-java-app-maven@0.1.0",
},
{
name: "POM project has explicit group ID without . in it",
pkg: pkg.Package{
Name: "example-java-app-maven",
Version: "0.1.0",
Language: pkg.Java,
Type: pkg.JavaPkg,
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
Manifest: &pkg.JavaManifest{
Main: map[string]string{
"Manifest-Version": "1.0",
},
},
PomProperties: &pkg.PomProperties{
Path: "META-INF/maven/org.anchore/example-java-app-maven/pom.properties",
ArtifactID: "example-java-app-maven",
Version: "0.1.0",
Extra: make(map[string]string),
},
PomProject: &pkg.PomProject{
GroupID: "commons",
},
},
},
expect: "pkg:maven/commons/example-java-app-maven@0.1.0",
},
{
name: "POM project has explicit group ID without . in it",
pkg: pkg.Package{
Name: "example-java-app-maven",
Version: "0.1.0",
Language: pkg.Java,
Type: pkg.JavaPkg,
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
Manifest: &pkg.JavaManifest{
Main: map[string]string{
"Manifest-Version": "1.0",
},
},
PomProperties: &pkg.PomProperties{
Path: "META-INF/maven/org.anchore/example-java-app-maven/pom.properties",
ArtifactID: "example-java-app-maven",
Version: "0.1.0",
Extra: make(map[string]string),
},
PomProject: &pkg.PomProject{
Parent: &pkg.PomParent{
GroupID: "parent",
},
},
},
},
expect: "pkg:maven/parent/example-java-app-maven@0.1.0",
},
}
for _, tt := range tests {
t.Run(tt.expect, func(t *testing.T) {
@@ -131,59 +45,3 @@ func Test_packageURL(t *testing.T) {
})
}
}
func Test_groupIDFromJavaMetadata(t *testing.T) {
tests := []struct {
name string
pkgName string
metadata pkg.JavaMetadata
expect string
}{
{
name: "pom properties",
metadata: pkg.JavaMetadata{
PomProperties: &pkg.PomProperties{
GroupID: "org.anchore",
},
},
expect: "org.anchore",
},
{
name: "pom project",
metadata: pkg.JavaMetadata{
PomProject: &pkg.PomProject{
GroupID: "org.anchore",
},
},
expect: "org.anchore",
},
{
name: "known package list",
pkgName: "ant-antlr",
metadata: pkg.JavaMetadata{},
expect: "org.apache.ant",
},
{
name: "java manifest",
metadata: pkg.JavaMetadata{
Manifest: &pkg.JavaManifest{
Main: map[string]string{
"Implementation-Vendor": "org.anchore",
},
},
},
expect: "org.anchore",
},
{
name: "no group id",
metadata: pkg.JavaMetadata{},
expect: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expect, groupIDFromJavaMetadata(tt.pkgName, tt.metadata))
})
}
}
+14 -64
View File
@@ -1,7 +1,6 @@
package java
import (
"bytes"
"encoding/xml"
"fmt"
"io"
@@ -9,11 +8,9 @@ import (
"regexp"
"strings"
"github.com/saintfish/chardet"
"github.com/vifraa/gopom"
"golang.org/x/net/html/charset"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
@@ -61,13 +58,12 @@ func newPomProject(path string, p gopom.Project) *pkg.PomProject {
artifactID := safeString(p.ArtifactID)
name := safeString(p.Name)
projectURL := safeString(p.URL)
log.WithFields("path", path, "artifactID", artifactID, "name", name, "projectURL", projectURL).Trace("parsing pom.xml")
return &pkg.PomProject{
Path: path,
Parent: pomParent(p, p.Parent),
GroupID: resolveProperty(p, p.GroupID, "groupId"),
GroupID: resolveProperty(p, p.GroupID),
ArtifactID: artifactID,
Version: resolveProperty(p, p.Version, "version"),
Version: resolveProperty(p, p.Version),
Name: name,
Description: cleanDescription(p.Description),
URL: projectURL,
@@ -77,14 +73,14 @@ func newPomProject(path string, p gopom.Project) *pkg.PomProject {
func newPackageFromPom(pom gopom.Project, dep gopom.Dependency, locations ...file.Location) pkg.Package {
m := pkg.JavaMetadata{
PomProperties: &pkg.PomProperties{
GroupID: resolveProperty(pom, dep.GroupID, "groupId"),
ArtifactID: resolveProperty(pom, dep.ArtifactID, "artifactId"),
Scope: resolveProperty(pom, dep.Scope, "scope"),
GroupID: resolveProperty(pom, dep.GroupID),
ArtifactID: resolveProperty(pom, dep.ArtifactID),
Scope: resolveProperty(pom, dep.Scope),
},
}
name := safeString(dep.ArtifactID)
version := resolveProperty(pom, dep.Version, "version")
version := resolveProperty(pom, dep.Version)
p := pkg.Package{
Name: name,
@@ -103,15 +99,9 @@ func newPackageFromPom(pom gopom.Project, dep gopom.Dependency, locations ...fil
}
func decodePomXML(content io.Reader) (project gopom.Project, err error) {
inputReader, err := getUtf8Reader(content)
if err != nil {
return project, fmt.Errorf("unable to read pom.xml: %w", err)
}
decoder := xml.NewDecoder(inputReader)
// when an xml file has a character set declaration (e.g. '<?xml version="1.0" encoding="ISO-8859-1"?>') read that and use the correct decoder
decoder := xml.NewDecoder(content)
// prevent against warnings for "xml: encoding "iso-8859-1" declared but Decoder.CharsetReader is nil"
decoder.CharsetReader = charset.NewReaderLabel
if err := decoder.Decode(&project); err != nil {
return project, fmt.Errorf("unable to unmarshal pom.xml: %w", err)
}
@@ -119,33 +109,6 @@ func decodePomXML(content io.Reader) (project gopom.Project, err error) {
return project, nil
}
func getUtf8Reader(content io.Reader) (io.Reader, error) {
pomContents, err := io.ReadAll(content)
if err != nil {
return nil, err
}
detector := chardet.NewTextDetector()
detection, err := detector.DetectBest(pomContents)
var inputReader io.Reader
if err == nil && detection != nil {
if detection.Charset == "UTF-8" {
inputReader = bytes.NewReader(pomContents)
} else {
inputReader, err = charset.NewReaderLabel(detection.Charset, bytes.NewReader(pomContents))
if err != nil {
return nil, fmt.Errorf("unable to get encoding: %w", err)
}
}
} else {
// we could not detect the encoding, but we want a valid file to read. Replace unreadable
// characters with the UTF-8 replacement character.
inputReader = strings.NewReader(strings.ToValidUTF8(string(pomContents), "�"))
}
return inputReader, nil
}
func pomParent(pom gopom.Project, parent *gopom.Parent) (result *pkg.PomParent) {
if parent == nil {
return nil
@@ -153,9 +116,9 @@ func pomParent(pom gopom.Project, parent *gopom.Parent) (result *pkg.PomParent)
artifactID := safeString(parent.ArtifactID)
result = &pkg.PomParent{
GroupID: resolveProperty(pom, parent.GroupID, "groupId"),
GroupID: resolveProperty(pom, parent.GroupID),
ArtifactID: artifactID,
Version: resolveProperty(pom, parent.Version, "version"),
Version: resolveProperty(pom, parent.Version),
}
if result.GroupID == "" && result.ArtifactID == "" && result.Version == "" {
@@ -184,11 +147,10 @@ func cleanDescription(original *string) (cleaned string) {
// If no match is found, the entire expression including ${} is returned
//
//nolint:gocognit
func resolveProperty(pom gopom.Project, property *string, propertyName string) string {
func resolveProperty(pom gopom.Project, property *string) string {
propertyCase := safeString(property)
log.WithFields("existingPropertyValue", propertyCase, "propertyName", propertyName).Trace("resolving property")
return propertyMatcher.ReplaceAllStringFunc(propertyCase, func(match string) string {
propertyName := strings.TrimSpace(match[2 : len(match)-1]) // remove leading ${ and trailing }
propertyName := strings.TrimSpace(match[2 : len(match)-1])
entries := pomProperties(pom)
if value, ok := entries[propertyName]; ok {
return value
@@ -210,26 +172,14 @@ func resolveProperty(pom gopom.Project, property *string, propertyName string) s
for fieldNum := 0; fieldNum < pomValueType.NumField(); fieldNum++ {
f := pomValueType.Field(fieldNum)
tag := f.Tag.Get("xml")
tag = strings.Split(tag, ",")[0]
// a segment of the property name matches the xml tag for the field,
// so we need to recurse down the nested structs or return a match
// if we're done.
tag = strings.TrimSuffix(tag, ",omitempty")
if part == tag {
pomValue = pomValue.Field(fieldNum)
pomValueType = pomValue.Type()
if pomValueType.Kind() == reflect.Ptr {
// we were recursing down the nested structs, but one of the steps
// we need to take is a nil pointer, so give up and return the original match
if pomValue.IsNil() {
return match
}
pomValue = pomValue.Elem()
if !pomValue.IsZero() {
// we found a non-zero value whose tag matches this part of the property name
pomValueType = pomValue.Type()
}
pomValueType = pomValue.Type()
}
// If this was the last part of the property name, return the value
if partNum == numParts-1 {
return fmt.Sprintf("%v", pomValue.Interface())
}
+1 -102
View File
@@ -1,14 +1,10 @@
package java
import (
"encoding/base64"
"io"
"os"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vifraa/gopom"
"github.com/anchore/syft/syft/file"
@@ -67,60 +63,6 @@ func Test_parserPomXML(t *testing.T) {
}
}
func Test_decodePomXML_surviveNonUtf8Encoding(t *testing.T) {
// regression for https://github.com/anchore/syft/issues/2044
// we are storing the base64 contents of the pom.xml file. We are doing this to prevent accidental changes to the
// file, which is extremely important for this test.
// for instance, even changing a single character in the file and saving in an IntelliJ IDE will automatically
// convert the file to UTF-8, which will break this test:
// xxd with the original pom.xml
// 00000780: 6964 3e0d 0a20 2020 2020 2020 2020 2020 id>..
// 00000790: 203c 6e61 6d65 3e4a e972 f46d 6520 4d69 <name>J.r.me Mi
// 000007a0: 7263 3c2f 6e61 6d65 3e0d 0a20 2020 2020 rc</name>..
// xxd with the pom.xml converted to UTF-8 (from a simple change with IntelliJ)
// 00000780: 6964 3e0d 0a20 2020 2020 2020 2020 2020 id>..
// 00000790: 203c 6e61 6d65 3e4a efbf bd72 efbf bd6d <name>J...r...m
// 000007a0: 6520 4d69 7263 3c2f 6e61 6d65 3e0d 0a20 e Mirc</name>..
// Note that the name "Jérôme Mirc" was originally interpreted as "J.r.me Mi" and after the save
// is now encoded as "J...r...m" which is not what we want (note the extra bytes for each non UTF-8 character.
// The original 0xe9 byte (é) was converted to 0xefbfbd (�) which is the UTF-8 replacement character.
// This is quite silly on the part of IntelliJ, but it is what it is.
cases := []struct {
name string
fixture string
}{
{
name: "undeclared encoding",
fixture: "test-fixtures/pom/undeclared-iso-8859-encoded-pom.xml.base64",
},
{
name: "declared encoding",
fixture: "test-fixtures/pom/declared-iso-8859-encoded-pom.xml.base64",
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
fh, err := os.Open(c.fixture)
require.NoError(t, err)
decoder := base64.NewDecoder(base64.StdEncoding, fh)
proj, err := decodePomXML(decoder)
require.NoError(t, err)
require.NotEmpty(t, proj.Developers)
})
}
}
func Test_parseCommonsTextPomXMLProject(t *testing.T) {
tests := []struct {
input string
@@ -446,29 +388,11 @@ func Test_resolveProperty(t *testing.T) {
},
expected: "org.some.parent",
},
{
name: "nil pointer halts search",
property: "${project.parent.groupId}",
pom: gopom.Project{
Parent: nil,
},
expected: "${project.parent.groupId}",
},
{
name: "nil string pointer halts search",
property: "${project.parent.groupId}",
pom: gopom.Project{
Parent: &gopom.Parent{
GroupID: nil,
},
},
expected: "${project.parent.groupId}",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
resolved := resolveProperty(test.pom, stringPointer(test.property), test.name)
resolved := resolveProperty(test.pom, stringPointer(test.property))
assert.Equal(t, test.expected, resolved)
})
}
@@ -477,28 +401,3 @@ func Test_resolveProperty(t *testing.T) {
func stringPointer(s string) *string {
return &s
}
func Test_getUtf8Reader(t *testing.T) {
tests := []struct {
name string
contents string
}{
{
name: "unknown encoding",
// random binary contents
contents: "BkiJz02JyEWE0nXR6TH///9NicpJweEETIucJIgAAABJicxPjQwhTY1JCE05WQh0BU2J0eunTYshTIusJIAAAAAPHwBNOeV1BUUx2+tWTIlUJDhMiUwkSEyJRCQgSIl8JFBMiQ==",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(tt.contents))
got, err := getUtf8Reader(decoder)
require.NoError(t, err)
gotBytes, err := io.ReadAll(got)
require.NoError(t, err)
// if we couldn't decode the section as UTF-8, we should get a replacement character
assert.Contains(t, string(gotBytes), "�")
})
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -7,7 +7,6 @@ type GolangBinMetadata struct {
Architecture string `json:"architecture" cyclonedx:"architecture"`
H1Digest string `json:"h1Digest,omitempty" cyclonedx:"h1Digest"`
MainModule string `json:"mainModule,omitempty" cyclonedx:"mainModule"`
GoCryptoSettings []string `json:"goCryptoSettings,omitempty" cyclonedx:"goCryptoSettings"`
}
// GolangModMetadata represents all captured data for a Golang source scan with go.mod/go.sum