Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add speculative OS CPEName #40

Merged
merged 5 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ require (
github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501
github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963
github.com/anchore/stereoscope v0.0.0-20230216143338-4b5ebf8c7f4b
github.com/anchore/syft v0.72.0
github.com/anchore/stereoscope v0.0.0-20230222185948-fab1c9638abc
github.com/anchore/syft v0.73.0
github.com/bmatcuk/doublestar/v2 v2.0.4
github.com/docker/docker v23.0.1+incompatible
github.com/dustin/go-humanize v1.0.1
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,10 @@ github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501 h1:AV7qjwM
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963 h1:vrf2PYH77vqVJoNR15ZuFJ63qwBMqrmGIt/7VsBhLF8=
github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963/go.mod h1:AVRyXOUP0hTz9Cb8OlD1XnwA8t4lBPfTuwPHmEUuiLc=
github.com/anchore/stereoscope v0.0.0-20230216143338-4b5ebf8c7f4b h1:vMEAfz91QLjJq2W8JPxpIC4dG4OeynTY4MisHnZ19F0=
github.com/anchore/stereoscope v0.0.0-20230216143338-4b5ebf8c7f4b/go.mod h1:6oSG43mzahqiktzXZDctqi1o66fwU2wDk3xki0KlnbA=
github.com/anchore/syft v0.72.0 h1:EpZMDitSElK/Qm1zgrL/3HM2Cw0hHo7hy9uwrhIXDGA=
github.com/anchore/syft v0.72.0/go.mod h1:T3ZSrApwb+jwI+vyTfE5R54Xej4NBoQ8c2t1LyJWGao=
github.com/anchore/stereoscope v0.0.0-20230222185948-fab1c9638abc h1:b+2KauWByrCPLNnzRHjLoUxo85tpszFtU7S1I5pAKK0=
github.com/anchore/stereoscope v0.0.0-20230222185948-fab1c9638abc/go.mod h1:Y+jiUa5PmQh9jUvzmvus4EvLnEG87cDTOYgV3nw3wDg=
github.com/anchore/syft v0.73.0 h1:htS03PVnCwvTuVEna2hpXcYrgOU4j+kB/l0rUAe0PW0=
github.com/anchore/syft v0.73.0/go.mod h1:oKRfCKZVYtzdWwaPzSvmTgTB7p71IwOUkK6B7/LsUZw=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
Expand Down
25 changes: 0 additions & 25 deletions internal/cpe/cpe.go

This file was deleted.

58 changes: 0 additions & 58 deletions internal/cpe/cpe_test.go

This file was deleted.

16 changes: 12 additions & 4 deletions xeol/db/eol_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (

"github.com/anchore/syft/syft/linux"

"github.com/noqcks/xeol/internal/cpe"
"github.com/noqcks/xeol/internal/purl"
xeolDB "github.com/noqcks/xeol/xeol/db/v1"
"github.com/noqcks/xeol/xeol/distro"
"github.com/noqcks/xeol/xeol/eol"
"github.com/noqcks/xeol/xeol/pkg"
)
Expand All @@ -24,14 +24,22 @@ func NewEolProvider(reader xeolDB.EolStoreReader) (*EolProvider, error) {
}, nil
}

func (pr *EolProvider) GetByDistroCpe(d *linux.Release) (string, []eol.Cycle, error) {
func (pr *EolProvider) GetByDistroCpe(r *linux.Release) (string, []eol.Cycle, error) {
cycles := make([]eol.Cycle, 0)
if r == nil {
return "", []eol.Cycle{}, errors.New("empty distro release")
}

d, err := distro.NewFromRelease(*r)
if err != nil {
return "", []eol.Cycle{}, err
}

if d == nil || d.CPEName == "" {
if d == nil || d.CPEName.String() == "" {
return "", []eol.Cycle{}, errors.New("empty distro CPEName")
}

shortCPE, version := cpe.Destructure(d.CPEName)
shortCPE, version := d.CPEName.Destructured()
if version == "" || shortCPE == "" {
return "", []eol.Cycle{}, errors.New("invalid distro CPEName")
}
Expand Down
33 changes: 33 additions & 0 deletions xeol/distro/cpe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package distro

import (
"strings"

"github.com/noqcks/xeol/internal/log"
)

// CPEName returns the CPE name for the distro.
type CPEName string

func (c CPEName) String() string {
return string(c)
}

// Destructured splits a CPE name into its (cpe:2.3:o:vendor:package) and version components.
func (c CPEName) Destructured() (shortCPE, version string) {
parts := strings.Split(c.String(), ":")

if len(parts) < 5 {
log.Debugf("CPE string '%s' is too short", c.String())
return "", ""
}

var splitIndex int
if parts[1] == "2.3" {
splitIndex = 5
} else {
splitIndex = 4
}

return strings.Join(parts[:splitIndex], ":"), parts[splitIndex]
}
9 changes: 7 additions & 2 deletions xeol/distro/distro.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ type Distro struct {
Version *hashiVer.Version
RawVersion string
IDLike []string
CPEName CPEName
}

// New creates a new Distro object populated with the given values.
func New(t Type, version string, idLikes ...string) (*Distro, error) {
func New(t Type, cpeName, version string, idLikes ...string) (*Distro, error) {
var verObj *hashiVer.Version
var err error

Expand All @@ -26,13 +27,17 @@ func New(t Type, version string, idLikes ...string) (*Distro, error) {
if err != nil {
return nil, fmt.Errorf("unable to parse version: %w", err)
}
if cpeName == "" {
cpeName = fmt.Sprintf("cpe:2.3:o:%s:%s:%s", t.CpeVendor(), t.CpeProduct(), version)
}
}

return &Distro{
Type: t,
Version: verObj,
RawVersion: version,
IDLike: idLikes,
CPEName: CPEName(cpeName),
}, nil
}

Expand All @@ -56,7 +61,7 @@ func NewFromRelease(release linux.Release) (*Distro, error) {
}
}

return New(t, selectedVersion, release.IDLike...)
return New(t, release.CPEName, selectedVersion, release.IDLike...)
}

func (d Distro) Name() string {
Expand Down
147 changes: 147 additions & 0 deletions xeol/distro/distro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func Test_NewDistroFromRelease(t *testing.T) {
release linux.Release
expectedVersion string
expectedRawVersion string
expectedCpe string
expectedType Type
expectErr bool
}{
Expand Down Expand Up @@ -333,3 +334,149 @@ func TestDistro_MajorVersion(t *testing.T) {
}

}

func TestDistro_CpeName(t *testing.T) {
tests := []struct {
fixture string
expectedCpe string
}{
{
fixture: "test-fixtures/os/ubuntu",
expectedCpe: "cpe:2.3:o:canonical:ubuntu_linux:20.04",
},
{
fixture: "test-fixtures/os/redhat",
expectedCpe: "cpe:/o:redhat:enterprise_linux:7.3:GA:server",
},
{
fixture: "test-fixtures/os/debian",
expectedCpe: "cpe:2.3:o:debian:debian_linux:8",
},
{
fixture: "test-fixtures/os/fedora",
expectedCpe: "cpe:/o:fedoraproject:fedora:31",
},
{
fixture: "test-fixtures/os/photon",
expectedCpe: "cpe:2.3:o:vmware:photon_os:2.0",
},
{
fixture: "test-fixtures/os/almalinux",
expectedCpe: "cpe:/o:almalinux:almalinux:8.4:GA",
},
{
fixture: "test-fixtures/os/alpine",
expectedCpe: "cpe:2.3:o:alpinelinux:alpine_linux:3.11.6",
},
{
fixture: "test-fixtures/os/amazon",
expectedCpe: "cpe:2.3:o:amazon:amazon_linux:2",
},
{
fixture: "test-fixtures/os/arch",
expectedCpe: "",
},
{
fixture: "test-fixtures/os/busybox",
expectedCpe: "cpe:2.3:o:busybox:busybox:1.31.1",
},
{
fixture: "test-fixtures/os/centos",
expectedCpe: "cpe:/o:centos:centos:8",
},
{
fixture: "test-fixtures/os/gentoo",
expectedCpe: "",
},
{
fixture: "test-fixtures/os/oraclelinux",
expectedCpe: "cpe:/o:oracle:linux:8:3:server",
},
{
fixture: "test-fixtures/os/opensuse-leap",
expectedCpe: "cpe:/o:opensuse:leap:15.2",
},
{
fixture: "test-fixtures/os/sles",
expectedCpe: "cpe:/o:suse:sles:15:sp2",
},
{
fixture: "test-fixtures/os/mariner",
expectedCpe: "cpe:2.3:o:microsoft:mariner:1.0",
},
}

for _, test := range tests {
t.Run(test.fixture, func(t *testing.T) {
s, err := source.NewFromDirectory(test.fixture)
require.NoError(t, err)

resolver, err := s.FileResolver(source.SquashedScope)
require.NoError(t, err)

// make certain syft and pick up on the raw information we need
release := linux.IdentifyRelease(resolver)
require.NotNil(t, release, "empty linux release info")

// craft a new distro from the syft raw info
d, err := NewFromRelease(*release)
require.NoError(t, err)

assert.Equal(t, d.CPEName.String(), test.expectedCpe)
})
}

}

func TestDistro_CpeNameDestructured(t *testing.T) {
testCases := []struct {
name string
input string
expectedShortCpe string
expectedVersion string
}{
{
name: "Exact CPE 2.2",
input: "cpe:/a:apache:struts:2.5.10",
expectedShortCpe: "cpe:/a:apache:struts",
expectedVersion: "2.5.10",
},
{
name: "Exact CPE 2.3",
input: "cpe:2.3:a:apache:struts:2.5.10",
expectedShortCpe: "cpe:2.3:a:apache:struts",
expectedVersion: "2.5.10",
},
{
name: "CPE 2.2",
input: "cpe:/a:apache:struts:2.5:*:*:*:*:*:*:*",
expectedShortCpe: "cpe:/a:apache:struts",
expectedVersion: "2.5",
},
{
name: "CPE 2.3",
input: "cpe:2.3:a:apache:struts:2.5:*:*:*:*:*:*:*",
expectedShortCpe: "cpe:2.3:a:apache:struts",
expectedVersion: "2.5",
},
{
name: "Empty CPE",
input: "",
expectedShortCpe: "",
expectedVersion: "",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
gotCpe, gotVersion := CPEName(tc.input).Destructured()

if gotVersion != tc.expectedVersion {
t.Errorf("Expected version '%v', got '%v'", tc.expectedVersion, gotVersion)
}
if gotCpe != tc.expectedShortCpe {
t.Errorf("Expected short CPE '%v', got '%v'", tc.expectedShortCpe, gotCpe)
}
})
}
}
Loading