mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 00:43:20 +01:00
add remaining debian & el distro support (#99)
This commit is contained in:
parent
5ccd6d5f6a
commit
63ba7ae47d
@ -12,21 +12,38 @@ import (
|
|||||||
// returns a distro or nil
|
// returns a distro or nil
|
||||||
type parseFunc func(string) *Distro
|
type parseFunc func(string) *Distro
|
||||||
|
|
||||||
|
type parseEntry struct {
|
||||||
|
path file.Path
|
||||||
|
fn parseFunc
|
||||||
|
}
|
||||||
|
|
||||||
// Identify parses distro-specific files to determine distro metadata like version and release
|
// Identify parses distro-specific files to determine distro metadata like version and release
|
||||||
func Identify(s scope.Scope) Distro {
|
func Identify(s scope.Scope) Distro {
|
||||||
distro := NewUnknownDistro()
|
distro := NewUnknownDistro()
|
||||||
|
|
||||||
identityFiles := map[file.Path]parseFunc{
|
identityFiles := []parseEntry{
|
||||||
"/etc/os-release": parseOsRelease,
|
{
|
||||||
// Debian and Debian-based distros have the same contents linked from this path
|
// most distros provide a link at this location
|
||||||
"/usr/lib/os-release": parseOsRelease,
|
path: "/etc/os-release",
|
||||||
"/bin/busybox": parseBusyBox,
|
fn: parseOsRelease,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// standard location for rhel & debian distros
|
||||||
|
path: "/usr/lib/os-release",
|
||||||
|
fn: parseOsRelease,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// check for busybox (important to check this last since other distros contain the busybox binary)
|
||||||
|
path: "/bin/busybox",
|
||||||
|
fn: parseBusyBox,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for path, fn := range identityFiles {
|
identifyLoop:
|
||||||
refs, err := s.FilesByPath(path)
|
for _, entry := range identityFiles {
|
||||||
|
refs, err := s.FilesByPath(entry.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("unable to get path refs from %s: %s", path, err)
|
log.Errorf("unable to get path refs from %s: %s", entry.path, err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,18 +61,18 @@ func Identify(s scope.Scope) Distro {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("unable to get contents from %s: %s", path, err)
|
log.Debugf("unable to get contents from %s: %s", entry.path, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if content == "" {
|
if content == "" {
|
||||||
log.Debugf("no contents in file, skipping: %s", path)
|
log.Debugf("no contents in file, skipping: %s", entry.path)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if candidateDistro := fn(content); candidateDistro != nil {
|
if candidateDistro := entry.fn(content); candidateDistro != nil {
|
||||||
distro = *candidateDistro
|
distro = *candidateDistro
|
||||||
break
|
break identifyLoop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,7 +81,7 @@ func Identify(s scope.Scope) Distro {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func assemble(name, version string) *Distro {
|
func assemble(name, version string) *Distro {
|
||||||
distroType, ok := Mappings[name]
|
distroType, ok := IDMapping[name]
|
||||||
|
|
||||||
// Both distro and version must be present
|
// Both distro and version must be present
|
||||||
if len(name) == 0 || len(version) == 0 {
|
if len(name) == 0 || len(version) == 0 {
|
||||||
|
|||||||
@ -6,45 +6,103 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/imgbom/internal"
|
||||||
|
|
||||||
"github.com/anchore/imgbom/imgbom/scope"
|
"github.com/anchore/imgbom/imgbom/scope"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIdentifyDistro(t *testing.T) {
|
func TestIdentifyDistro(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
fixture string
|
fixture string
|
||||||
name string
|
|
||||||
RawVersion string
|
|
||||||
Type Type
|
Type Type
|
||||||
|
Version string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
fixture: "test-fixtures/os/ubuntu-20.04",
|
fixture: "test-fixtures/os/alpine",
|
||||||
name: "ubuntu",
|
Type: Alpine,
|
||||||
|
Version: "3.11.6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fixture: "test-fixtures/os/amazon",
|
||||||
|
Type: AmazonLinux,
|
||||||
|
Version: "2.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fixture: "test-fixtures/os/busybox",
|
||||||
|
Type: Busybox,
|
||||||
|
Version: "1.31.1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fixture: "test-fixtures/os/centos",
|
||||||
|
Type: CentOS,
|
||||||
|
Version: "8.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fixture: "test-fixtures/os/debian",
|
||||||
|
Type: Debian,
|
||||||
|
Version: "8.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fixture: "test-fixtures/os/fedora",
|
||||||
|
Type: Fedora,
|
||||||
|
Version: "31.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fixture: "test-fixtures/os/redhat",
|
||||||
|
Type: RedHat,
|
||||||
|
Version: "7.3.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fixture: "test-fixtures/os/ubuntu",
|
||||||
Type: Ubuntu,
|
Type: Ubuntu,
|
||||||
|
Version: "20.4.0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fixture: "test-fixtures/os/empty",
|
fixture: "test-fixtures/os/empty",
|
||||||
name: "No OS files",
|
|
||||||
Type: UnknownDistroType,
|
Type: UnknownDistroType,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fixture: "test-fixtures/os/unmatchable",
|
fixture: "test-fixtures/os/unmatchable",
|
||||||
name: "Unmatchable distro",
|
|
||||||
Type: UnknownDistroType,
|
Type: UnknownDistroType,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observedDistros := internal.NewStringSet()
|
||||||
|
definedDistros := internal.NewStringSet()
|
||||||
|
for _, d := range All {
|
||||||
|
definedDistros.Add(d.String())
|
||||||
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.fixture, func(t *testing.T) {
|
||||||
s, err := scope.NewScopeFromDir(test.fixture, scope.AllLayersScope)
|
s, err := scope.NewScopeFromDir(test.fixture, scope.AllLayersScope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to produce a new scope for testing: %s", test.fixture)
|
t.Fatalf("unable to produce a new scope for testing: %s", test.fixture)
|
||||||
}
|
}
|
||||||
distro := Identify(s)
|
|
||||||
if distro.Type != test.Type {
|
d := Identify(s)
|
||||||
t.Errorf("expected distro doesn't match: %v != %v", distro.Type, test.Type)
|
observedDistros.Add(d.String())
|
||||||
|
|
||||||
|
if d.Type != test.Type {
|
||||||
|
t.Errorf("expected distro doesn't match: %v != %v", d.Type, test.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Type == UnknownDistroType && d.Version != nil {
|
||||||
|
t.Fatalf("version should be nil for unknown distros")
|
||||||
|
} else if d.Type == UnknownDistroType && d.Version == nil {
|
||||||
|
// don't check versions for unknown distro types
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Version.String() != test.Version {
|
||||||
|
t.Errorf("expected distro version doesn't match: %v != %v", d.Version.String(), test.Version)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that test cases stay in sync with the distros that can be identified
|
||||||
|
if len(observedDistros) < len(definedDistros) {
|
||||||
|
t.Errorf("distro coverage incomplete (distro=%d, coverage=%d)", len(definedDistros), len(observedDistros))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -86,11 +144,10 @@ func TestParseOsRelease(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
name := fmt.Sprintf("%s:%s", test.name, test.RawVersion)
|
name := fmt.Sprintf("%s:%s", test.name, test.RawVersion)
|
||||||
fixture, err := os.Open(test.fixture)
|
fixture, err := os.Open(test.fixture)
|
||||||
defer fixture.Close()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to open fixture: %+v", err)
|
t.Fatalf("could not open test fixture=%s: %+v", test.fixture, err)
|
||||||
}
|
}
|
||||||
|
defer fixture.Close()
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(fixture)
|
b, err := ioutil.ReadAll(fixture)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -131,11 +188,10 @@ func TestParseOsReleaseFailures(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
name := fmt.Sprintf("%s:%s", test.name, test.fixture)
|
name := fmt.Sprintf("%s:%s", test.name, test.fixture)
|
||||||
fixture, err := os.Open(test.fixture)
|
fixture, err := os.Open(test.fixture)
|
||||||
defer fixture.Close()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to open fixture: %+v", err)
|
t.Fatalf("could not open test fixture=%s: %+v", test.fixture, err)
|
||||||
}
|
}
|
||||||
|
defer fixture.Close()
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(fixture)
|
b, err := ioutil.ReadAll(fixture)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
6
imgbom/distro/test-fixtures/os/alpine/etc/os-release
Normal file
6
imgbom/distro/test-fixtures/os/alpine/etc/os-release
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
NAME="Alpine Linux"
|
||||||
|
ID=alpine
|
||||||
|
VERSION_ID=3.11.6
|
||||||
|
PRETTY_NAME="Alpine Linux v3.11"
|
||||||
|
HOME_URL="https://alpinelinux.org/"
|
||||||
|
BUG_REPORT_URL="https://bugs.alpinelinux.org/"
|
||||||
9
imgbom/distro/test-fixtures/os/amazon/etc/os-release
Normal file
9
imgbom/distro/test-fixtures/os/amazon/etc/os-release
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
NAME="Amazon Linux"
|
||||||
|
VERSION="2"
|
||||||
|
ID="amzn"
|
||||||
|
ID_LIKE="centos rhel fedora"
|
||||||
|
VERSION_ID="2"
|
||||||
|
PRETTY_NAME="Amazon Linux 2"
|
||||||
|
ANSI_COLOR="0;33"
|
||||||
|
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
|
||||||
|
HOME_URL="https://amazonlinux.com/"
|
||||||
1
imgbom/distro/test-fixtures/os/busybox/bin/busybox
Normal file
1
imgbom/distro/test-fixtures/os/busybox/bin/busybox
Normal file
@ -0,0 +1 @@
|
|||||||
|
junk...BusyBox v1.31.1more junk
|
||||||
16
imgbom/distro/test-fixtures/os/centos/usr/lib/os-release
Normal file
16
imgbom/distro/test-fixtures/os/centos/usr/lib/os-release
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
NAME="CentOS Linux"
|
||||||
|
VERSION="8 (Core)"
|
||||||
|
ID="centos"
|
||||||
|
ID_LIKE="rhel fedora"
|
||||||
|
VERSION_ID="8"
|
||||||
|
PLATFORM_ID="platform:el8"
|
||||||
|
PRETTY_NAME="CentOS Linux 8 (Core)"
|
||||||
|
ANSI_COLOR="0;31"
|
||||||
|
CPE_NAME="cpe:/o:centos:centos:8"
|
||||||
|
HOME_URL="https://www.centos.org/"
|
||||||
|
BUG_REPORT_URL="https://bugs.centos.org/"
|
||||||
|
|
||||||
|
CENTOS_MANTISBT_PROJECT="CentOS-8"
|
||||||
|
CENTOS_MANTISBT_PROJECT_VERSION="8"
|
||||||
|
REDHAT_SUPPORT_PRODUCT="centos"
|
||||||
|
REDHAT_SUPPORT_PRODUCT_VERSION="8"
|
||||||
8
imgbom/distro/test-fixtures/os/debian/usr/lib/os-release
Normal file
8
imgbom/distro/test-fixtures/os/debian/usr/lib/os-release
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
|
||||||
|
NAME="Debian GNU/Linux"
|
||||||
|
VERSION_ID="8"
|
||||||
|
VERSION="8 (jessie)"
|
||||||
|
ID=debian
|
||||||
|
HOME_URL="http://www.debian.org/"
|
||||||
|
SUPPORT_URL="http://www.debian.org/support"
|
||||||
|
BUG_REPORT_URL="https://bugs.debian.org/"
|
||||||
21
imgbom/distro/test-fixtures/os/fedora/usr/lib/os-release
Normal file
21
imgbom/distro/test-fixtures/os/fedora/usr/lib/os-release
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
NAME=Fedora
|
||||||
|
VERSION="31 (Container Image)"
|
||||||
|
ID=fedora
|
||||||
|
VERSION_ID=31
|
||||||
|
VERSION_CODENAME=""
|
||||||
|
PLATFORM_ID="platform:f31"
|
||||||
|
PRETTY_NAME="Fedora 31 (Container Image)"
|
||||||
|
ANSI_COLOR="0;34"
|
||||||
|
LOGO=fedora-logo-icon
|
||||||
|
CPE_NAME="cpe:/o:fedoraproject:fedora:31"
|
||||||
|
HOME_URL="https://fedoraproject.org/"
|
||||||
|
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f31/system-administrators-guide/"
|
||||||
|
SUPPORT_URL="https://fedoraproject.org/wiki/Communicating_and_getting_help"
|
||||||
|
BUG_REPORT_URL="https://bugzilla.redhat.com/"
|
||||||
|
REDHAT_BUGZILLA_PRODUCT="Fedora"
|
||||||
|
REDHAT_BUGZILLA_PRODUCT_VERSION=31
|
||||||
|
REDHAT_SUPPORT_PRODUCT="Fedora"
|
||||||
|
REDHAT_SUPPORT_PRODUCT_VERSION=31
|
||||||
|
PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy"
|
||||||
|
VARIANT="Container Image"
|
||||||
|
VARIANT_ID=container
|
||||||
15
imgbom/distro/test-fixtures/os/redhat/usr/lib/os-release
Normal file
15
imgbom/distro/test-fixtures/os/redhat/usr/lib/os-release
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
NAME="Red Hat Enterprise Linux Server"
|
||||||
|
VERSION="7.3 (Maipo)"
|
||||||
|
ID="rhel"
|
||||||
|
ID_LIKE="fedora"
|
||||||
|
VERSION_ID="7.3"
|
||||||
|
PRETTY_NAME="Red Hat Enterprise Linux Server 7.3 (Maipo)"
|
||||||
|
ANSI_COLOR="0;31"
|
||||||
|
CPE_NAME="cpe:/o:redhat:enterprise_linux:7.3:GA:server"
|
||||||
|
HOME_URL="https://www.redhat.com/"
|
||||||
|
BUG_REPORT_URL="https://bugzilla.redhat.com/"
|
||||||
|
|
||||||
|
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 7"
|
||||||
|
REDHAT_BUGZILLA_PRODUCT_VERSION=7.3
|
||||||
|
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
|
||||||
|
REDHAT_SUPPORT_PRODUCT_VERSION="7.3"
|
||||||
@ -6,19 +6,14 @@ const (
|
|||||||
Ubuntu
|
Ubuntu
|
||||||
RedHat
|
RedHat
|
||||||
CentOS
|
CentOS
|
||||||
// Fedora
|
Fedora
|
||||||
// Alpine
|
Alpine
|
||||||
Busybox
|
Busybox
|
||||||
// AmazonLinux
|
AmazonLinux
|
||||||
// OracleLinux
|
OracleLinux
|
||||||
//ArchLinux
|
//ArchLinux
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// UnknownVersion is a default of 0.0.0 when it can't be parsed
|
|
||||||
UnknownVersion string = "0.0.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Type int
|
type Type int
|
||||||
|
|
||||||
var distroStr = []string{
|
var distroStr = []string{
|
||||||
@ -27,11 +22,11 @@ var distroStr = []string{
|
|||||||
"ubuntu",
|
"ubuntu",
|
||||||
"redhat",
|
"redhat",
|
||||||
"centos",
|
"centos",
|
||||||
// "fedora",
|
"fedora",
|
||||||
// "alpine",
|
"alpine",
|
||||||
"busybox",
|
"busybox",
|
||||||
// "amazn",
|
"amazn",
|
||||||
// "oraclelinux",
|
"oraclelinux",
|
||||||
//"archlinux",
|
//"archlinux",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,11 +35,11 @@ var All = []Type{
|
|||||||
Ubuntu,
|
Ubuntu,
|
||||||
RedHat,
|
RedHat,
|
||||||
CentOS,
|
CentOS,
|
||||||
// Fedora,
|
Fedora,
|
||||||
// Alpine,
|
Alpine,
|
||||||
Busybox,
|
Busybox,
|
||||||
// AmazonLinux,
|
AmazonLinux,
|
||||||
// OracleLinux,
|
OracleLinux,
|
||||||
//ArchLinux,
|
//ArchLinux,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,16 +51,16 @@ func (t Type) String() string {
|
|||||||
return distroStr[t]
|
return distroStr[t]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mappings connects a distro ID like "ubuntu" to a Distro type
|
// IDMapping connects a distro ID like "ubuntu" to a Distro type
|
||||||
var Mappings = map[string]Type{
|
var IDMapping = map[string]Type{
|
||||||
"debian": Debian,
|
"debian": Debian,
|
||||||
"ubuntu": Ubuntu,
|
"ubuntu": Ubuntu,
|
||||||
"rhel": RedHat,
|
"rhel": RedHat,
|
||||||
"centos": CentOS,
|
"centos": CentOS,
|
||||||
// "fedora": Fedora,
|
"fedora": Fedora,
|
||||||
// "alpine": Alpine,
|
"alpine": Alpine,
|
||||||
"busybox": Busybox,
|
"busybox": Busybox,
|
||||||
// "amazn": AmazonLinux,
|
"amzn": AmazonLinux,
|
||||||
// "oraclelinux": OracleLinux,
|
"ol": OracleLinux,
|
||||||
// "archlinux": ArchLinux,
|
//"arch": ArchLinux,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,8 +29,13 @@ func Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scop
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IdentifyDistro(s scope.Scope) distro.Distro {
|
func IdentifyDistro(s scope.Scope) distro.Distro {
|
||||||
log.Info("Identifying Distro")
|
d := distro.Identify(s)
|
||||||
return distro.Identify(s)
|
if d.Type != distro.UnknownDistroType {
|
||||||
|
log.Infof("Identified Distro: %s", d.String())
|
||||||
|
} else {
|
||||||
|
log.Info("Could not identify distro")
|
||||||
|
}
|
||||||
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
func CatalogFromScope(s scope.Scope) (*pkg.Catalog, error) {
|
func CatalogFromScope(s scope.Scope) (*pkg.Catalog, error) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user