Skip to content

Commit

Permalink
address review comments
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
  • Loading branch information
wagoodman committed Oct 30, 2024
1 parent 4b48e7f commit abb030a
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 21 deletions.
2 changes: 1 addition & 1 deletion cmd/grype/cli/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ You can also explicitly specify the scheme to use:
{{.appName}} sbom:path/to/syft.json read Syft JSON from path on disk
{{.appName}} registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
{{.appName}} purl:path/to/purl/file read a newline separated file of package URLs from a path on disk
{{.appName}} pkg:PURL read a single package PURL directly (e.g. pkg:apk/openssl@3.2.1?distro=alpine-3.20.3)
{{.appName}} PURL read a single package PURL directly (e.g. pkg:apk/openssl@3.2.1?distro=alpine-3.20.3)
You can also pipe in Syft JSON directly:
syft yourimage:tag -o json | {{.appName}}
Expand Down
43 changes: 23 additions & 20 deletions grype/pkg/purl_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,16 @@ func decodePurlFile(reader io.Reader) ([]Package, Context, error) {
distros := make(map[string]*strset.Set)
for scanner.Scan() {
rawLine := scanner.Text()
p, err := purlToPackage(rawLine, distros)
p, distroName, distroVersion, err := purlToPackage(rawLine)
if err != nil {
return nil, Context{}, err
}
if distroName != "" {
if _, ok := distros[distroName]; !ok {
distros[distroName] = strset.New()
}
distros[distroName].Add(distroVersion)
}
if p != nil {
packages = append(packages, *p)
}
Expand Down Expand Up @@ -77,15 +83,16 @@ func decodePurlFile(reader io.Reader) ([]Package, Context, error) {
return packages, ctx, nil
}

func purlToPackage(rawLine string, distros map[string]*strset.Set) (*Package, error) {
func purlToPackage(rawLine string) (*Package, string, string, error) {
purl, err := packageurl.FromString(rawLine)
if err != nil {
return nil, fmt.Errorf("unable to decode purl %s: %w", rawLine, err)
return nil, "", "", fmt.Errorf("unable to decode purl %s: %w", rawLine, err)
}

cpes := []cpe.CPE{}
epoch := "0"
var cpes []cpe.CPE
var upstreams []UpstreamPackage
var distroName, distroVersion string
epoch := "0"

pkgType := pkg.TypeByName(purl.Type)

Expand All @@ -96,7 +103,7 @@ func purlToPackage(rawLine string, distros map[string]*strset.Set) (*Package, er
for _, rawCpe := range rawCpes {
c, err := cpe.New(rawCpe, "")
if err != nil {
return nil, fmt.Errorf("unable to decode cpe %s in purl %s: %w", rawCpe, rawLine, err)
return nil, "", "", fmt.Errorf("unable to decode cpe %s in purl %s: %w", rawCpe, rawLine, err)
}
cpes = append(cpes, c)
}
Expand All @@ -106,29 +113,28 @@ func purlToPackage(rawLine string, distros map[string]*strset.Set) (*Package, er
upstreams = append(upstreams, parseUpstream(purl.Name, qualifier.Value, pkgType)...)
case pkg.PURLQualifierDistro:
name, version := parseDistroQualifier(qualifier.Value)
if name != "" {
if _, ok := distros[name]; !ok {
distros[name] = strset.New()
}
distros[name].Add(version)
if name != "" && version != "" {
distroName = name
distroVersion = version
}
}
}

version := purl.Version
if purl.Type == packageurl.TypeRPM && !strings.HasPrefix(purl.Version, fmt.Sprintf("%s:", epoch)) {
purl.Version = fmt.Sprintf("%s:%s", epoch, purl.Version)
version = fmt.Sprintf("%s:%s", epoch, purl.Version)
}

return &Package{
ID: ID(purl.String()),
CPEs: cpes,
Name: purl.Name,
Version: purl.Version,
Version: version,
Type: pkgType,
Language: pkg.LanguageByName(purl.Type),
PURL: purl.String(),
Upstreams: upstreams,
}, nil
}, distroName, distroVersion, nil
}

func parseDistroQualifier(value string) (string, string) {
Expand All @@ -143,16 +149,13 @@ func parseDistroQualifier(value string) (string, string) {
}

func parseUpstream(pkgName string, value string, pkgType pkg.Type) []UpstreamPackage {
switch pkgType {
case pkg.RpmPkg:
if pkgType == pkg.RpmPkg {
return handleSourceRPM(pkgName, value)
case pkg.DebPkg:
return handleDebianSource(pkgName, value)
}
return nil
return handleDefaultUpstream(pkgName, value)
}

func handleDebianSource(pkgName string, value string) []UpstreamPackage {
func handleDefaultUpstream(pkgName string, value string) []UpstreamPackage {
fields := strings.Split(value, "@")
switch len(fields) {
case 2:
Expand Down
89 changes: 89 additions & 0 deletions grype/pkg/purl_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,95 @@ func Test_PurlProvider(t *testing.T) {
},
},
},
{
name: "default upstream",
userInput: "pkg:apk/libcrypto3@3.3.2?upstream=openssl",
context: Context{},
pkgs: []Package{
{
Name: "libcrypto3",
Version: "3.3.2",
Type: pkg.ApkPkg,
PURL: "pkg:apk/libcrypto3@3.3.2?upstream=openssl",
Upstreams: []UpstreamPackage{
{
Name: "openssl",
},
},
},
},
},
{
name: "upstream with version",
userInput: "pkg:apk/libcrypto3@3.3.2?upstream=openssl%403.2.1", // %40 is @
context: Context{},
pkgs: []Package{
{
Name: "libcrypto3",
Version: "3.3.2",
Type: pkg.ApkPkg,
PURL: "pkg:apk/libcrypto3@3.3.2?upstream=openssl%403.2.1",
Upstreams: []UpstreamPackage{
{
Name: "openssl",
Version: "3.2.1",
},
},
},
},
},
{
name: "upstream for source RPM",
userInput: "pkg:rpm/redhat/systemd-x@239-82.el8_10.2?arch=aarch64&distro=rhel-8.10&upstream=systemd-239-82.el8_10.2.src.rpm",
context: Context{
Distro: &linux.Release{
Name: "rhel",
ID: "rhel",
IDLike: []string{"rhel"},
Version: "8.10",
},
},
pkgs: []Package{
{
Name: "systemd-x",
Version: "0:239-82.el8_10.2",
Type: pkg.RpmPkg,
PURL: "pkg:rpm/redhat/systemd-x@239-82.el8_10.2?arch=aarch64&distro=rhel-8.10&upstream=systemd-239-82.el8_10.2.src.rpm",
Upstreams: []UpstreamPackage{
{
Name: "systemd",
Version: "239-82.el8_10.2",
},
},
},
},
},
{
name: "RPM with epoch",
userInput: "pkg:rpm/redhat/dbus-common@1.12.8-26.el8?arch=noarch&distro=rhel-8.10&epoch=1&upstream=dbus-1.12.8-26.el8.src.rpm",
context: Context{
Distro: &linux.Release{
Name: "rhel",
ID: "rhel",
IDLike: []string{"rhel"},
Version: "8.10",
},
},
pkgs: []Package{
{
Name: "dbus-common",
Version: "1:1.12.8-26.el8",
Type: pkg.RpmPkg,
PURL: "pkg:rpm/redhat/dbus-common@1.12.8-26.el8?arch=noarch&distro=rhel-8.10&epoch=1&upstream=dbus-1.12.8-26.el8.src.rpm",
Upstreams: []UpstreamPackage{
{
Name: "dbus",
Version: "1.12.8-26.el8",
},
},
},
},
},
{
name: "takes multiple purls",
userInput: "purl:test-fixtures/purl/valid-purl.txt",
Expand Down

0 comments on commit abb030a

Please sign in to comment.