Add support for dependency relationships for alpine (apk) (#1063)

* Fix type of pull deps and add support for provides

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* [wip] apk dependency lookup

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update whitespace for linter

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

* adjust test conditions

Signed-off-by: Timothy Gerla <tim@gerla.net>

* fix TODOs and improve Provides parser

* run simports after main merge

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

* add tests to cover apk relationship parsing cases

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* generate JSON schema for breaking changes to apk metadata

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update tests to account for additional dependencies

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* [wip] fix relationship encoding for cyclonedx

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* simplify package relationships that can be expressed

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Dan Luhring <dan+github@luhrings.com>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Signed-off-by: Timothy Gerla <tim@gerla.net>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
Co-authored-by: Timothy Gerla <tim@gerla.net>
This commit is contained in:
Dan Luhring 2022-11-09 10:43:37 -05:00 committed by GitHub
parent e58d0aecb8
commit 949cff158d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 2625 additions and 145 deletions

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 = "5.1.0"
JSONSchemaVersion = "6.0.0"
)

View File

@ -1571,4 +1571,4 @@
"type": "object"
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -10,15 +10,6 @@ const (
// ContainsRelationship (supports any-to-any linkages) is a proxy for the SPDX 2.2 CONTAINS relationship.
ContainsRelationship RelationshipType = "contains"
// RuntimeDependencyOfRelationship is a proxy for the SPDX 2.2.1 RUNTIME_DEPENDENCY_OF relationship.
RuntimeDependencyOfRelationship RelationshipType = "runtime-dependency-of"
// DevDependencyOfRelationship is a proxy for the SPDX 2.2.1 DEV_DEPENDENCY_OF relationship.
DevDependencyOfRelationship RelationshipType = "dev-dependency-of"
// BuildDependencyOfRelationship is a proxy for the SPDX 2.2.1 BUILD_DEPENDENCY_OF relationship.
BuildDependencyOfRelationship RelationshipType = "build-dependency-of"
// DependencyOfRelationship is a proxy for the SPDX 2.2.1 DEPENDENCY_OF relationship.
DependencyOfRelationship RelationshipType = "dependency-of"
)

View File

@ -31,20 +31,21 @@ func Test_encodeComponentProperties(t *testing.T) {
source.Location{Coordinates: source.Coordinates{RealPath: "test"}},
),
Metadata: pkg.ApkMetadata{
Package: "libc-utils",
OriginPackage: "libc-dev",
Maintainer: "Natanael Copa <ncopa@alpinelinux.org>",
Version: "0.7.2-r0",
License: "BSD",
Architecture: "x86_64",
URL: "http://alpinelinux.org",
Description: "Meta package to pull in correct libc",
Size: 0,
InstalledSize: 4096,
PullDependencies: "musl-utils",
PullChecksum: "Q1p78yvTLG094tHE1+dToJGbmYzQE=",
GitCommitOfAport: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479",
Files: []pkg.ApkFileRecord{},
Package: "libc-utils",
OriginPackage: "libc-dev",
Maintainer: "Natanael Copa <ncopa@alpinelinux.org>",
Version: "0.7.2-r0",
License: "BSD",
Architecture: "x86_64",
URL: "http://alpinelinux.org",
Description: "Meta package to pull in correct libc",
Size: 0,
InstalledSize: 4096,
Dependencies: []string{"musl-utils"},
Provides: []string{"so:libc.so.1"},
Checksum: "Q1p78yvTLG094tHE1+dToJGbmYzQE=",
GitCommit: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479",
Files: []pkg.ApkFileRecord{},
},
},
expected: &[]cyclonedx.Property{
@ -53,8 +54,9 @@ func Test_encodeComponentProperties(t *testing.T) {
{Name: "syft:metadata:gitCommitOfApkPort", Value: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479"},
{Name: "syft:metadata:installedSize", Value: "4096"},
{Name: "syft:metadata:originPackage", Value: "libc-dev"},
{Name: "syft:metadata:provides:0", Value: "so:libc.so.1"},
{Name: "syft:metadata:pullChecksum", Value: "Q1p78yvTLG094tHE1+dToJGbmYzQE="},
{Name: "syft:metadata:pullDependencies", Value: "musl-utils"},
{Name: "syft:metadata:pullDependencies:0", Value: "musl-utils"},
{Name: "syft:metadata:size", Value: "0"},
},
},

View File

@ -6,6 +6,7 @@ import (
"github.com/CycloneDX/cyclonedx-go"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/formats/common"
"github.com/anchore/syft/syft/linux"
@ -88,6 +89,10 @@ func collectPackages(component *cyclonedx.Component, s *sbom.SBOM, idMap map[str
case cyclonedx.ComponentTypeApplication, cyclonedx.ComponentTypeFramework, cyclonedx.ComponentTypeLibrary:
p := decodeComponent(component)
idMap[component.BOMRef] = p
syftID := extractSyftPacakgeID(component.BOMRef)
if syftID != "" {
idMap[syftID] = p
}
// TODO there must be a better way than needing to call this manually:
p.SetID()
s.Artifacts.PackageCatalog.Add(*p)
@ -100,6 +105,19 @@ func collectPackages(component *cyclonedx.Component, s *sbom.SBOM, idMap map[str
}
}
func extractSyftPacakgeID(i string) string {
instance, err := packageurl.FromString(i)
if err != nil {
return ""
}
for _, q := range instance.Qualifiers {
if q.Key == "package-id" {
return q.Value
}
}
return ""
}
func linuxReleaseFromComponents(components []cyclonedx.Component) *linux.Release {
for i := range components {
component := &components[i]
@ -188,21 +206,25 @@ func collectRelationships(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]int
return
}
for _, d := range *bom.Dependencies {
from, fromOk := idMap[d.Ref].(artifact.Identifiable)
if fromOk {
if d.Dependencies == nil {
from, fromExists := idMap[d.Ref].(artifact.Identifiable)
if !fromExists {
continue
}
if d.Dependencies == nil {
continue
}
for _, t := range *d.Dependencies {
to, toExists := idMap[t.Ref].(artifact.Identifiable)
if !toExists {
continue
}
for _, t := range *d.Dependencies {
to, toOk := idMap[t.Ref].(artifact.Identifiable)
if toOk {
s.Relationships = append(s.Relationships, artifact.Relationship{
From: from,
To: to,
Type: artifact.DependencyOfRelationship, // FIXME this information is lost
})
}
}
s.Relationships = append(s.Relationships, artifact.Relationship{
From: from,
To: to,
Type: artifact.DependencyOfRelationship, // FIXME this information is lost
})
}
}
}

View File

@ -10,6 +10,7 @@ import (
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
)
@ -120,16 +121,11 @@ func toBomDescriptor(name, version string, srcMetadata source.Metadata) *cyclone
// An example of a relationship to not include would be: OwnershipByFileOverlapRelationship.
func isExpressiblePackageRelationship(ty artifact.RelationshipType) bool {
switch ty {
case artifact.RuntimeDependencyOfRelationship:
return true
case artifact.DevDependencyOfRelationship:
return true
case artifact.BuildDependencyOfRelationship:
return true
case artifact.DependencyOfRelationship:
return true
default:
return false
}
return false
}
func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependency {
@ -141,10 +137,21 @@ func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependenc
continue
}
// we only capture package-to-package relationships for now
fromPkg, ok := r.From.(*pkg.Package)
if !ok {
continue
}
toPkg, ok := r.To.(*pkg.Package)
if !ok {
continue
}
innerDeps := []cyclonedx.Dependency{}
innerDeps = append(innerDeps, cyclonedx.Dependency{Ref: string(r.From.ID())})
innerDeps = append(innerDeps, cyclonedx.Dependency{Ref: deriveBomRef(*fromPkg)})
result = append(result, cyclonedx.Dependency{
Ref: string(r.To.ID()),
Ref: deriveBomRef(*toPkg),
Dependencies: &innerDeps,
})
}

View File

@ -186,16 +186,10 @@ func toSyftRelationships(spdxIDMap map[string]interface{}, doc *spdx.Document2_2
case ContainsRelationship:
typ = artifact.ContainsRelationship
to = toPackage
case BuildDependencyOfRelationship:
typ = artifact.BuildDependencyOfRelationship
to = toPackage
case RuntimeDependencyOfRelationship:
typ = artifact.RuntimeDependencyOfRelationship
to = toPackage
case OtherRelationship:
// Encoding uses a specifically formatted comment...
if strings.Index(r.RelationshipComment, string(artifact.OwnershipByFileOverlapRelationship)) == 0 {
typ = artifact.RuntimeDependencyOfRelationship
typ = artifact.DependencyOfRelationship
to = toPackage
}
}

View File

@ -4,7 +4,7 @@ import (
"github.com/anchore/syft/syft/sbom"
)
const ID sbom.FormatID = "syft-5-json"
const ID sbom.FormatID = "syft-6-json"
func Format() sbom.Format {
return sbom.NewFormat(

View File

@ -89,7 +89,7 @@
}
},
"schema": {
"version": "5.1.0",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-5.1.0.json"
"version": "6.0.0",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-6.0.0.json"
}
}

View File

@ -185,7 +185,7 @@
}
},
"schema": {
"version": "5.1.0",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-5.1.0.json"
"version": "6.0.0",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-6.0.0.json"
}
}

View File

@ -112,7 +112,7 @@
}
},
"schema": {
"version": "5.1.0",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-5.1.0.json"
"version": "6.0.0",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-6.0.0.json"
}
}

View File

@ -1,6 +1,8 @@
package syftjson
import (
"strings"
"github.com/google/go-cmp/cmp"
"github.com/anchore/syft/internal/log"
@ -113,12 +115,15 @@ func toSyftRelationship(idMap map[string]interface{}, relationship model.Relatio
typ := artifact.RelationshipType(relationship.Type)
switch typ {
case artifact.OwnershipByFileOverlapRelationship:
fallthrough
case artifact.ContainsRelationship:
case artifact.OwnershipByFileOverlapRelationship, artifact.ContainsRelationship, artifact.DependencyOfRelationship:
default:
log.Warnf("unknown relationship type: %s", typ)
return nil
if !strings.Contains(string(typ), "dependency-of") {
log.Warnf("unknown relationship type: %s", typ)
return nil
}
// lets try to stay as compatible as possible with similar relationship types without dropping the relationship
log.Warnf("assuming %q for relationship type %q", artifact.DependencyOfRelationship, typ)
typ = artifact.DependencyOfRelationship
}
return &artifact.Relationship{
From: from,

View File

@ -18,20 +18,21 @@ var _ FileOwner = (*ApkMetadata)(nil)
// - https://git.alpinelinux.org/apk-tools/tree/src/package.c
// - https://git.alpinelinux.org/apk-tools/tree/src/database.c
type ApkMetadata struct {
Package string `mapstructure:"P" json:"package"`
OriginPackage string `mapstructure:"o" json:"originPackage" cyclonedx:"originPackage"`
Maintainer string `mapstructure:"m" json:"maintainer"`
Version string `mapstructure:"V" json:"version"`
License string `mapstructure:"L" json:"license"`
Architecture string `mapstructure:"A" json:"architecture"`
URL string `mapstructure:"U" json:"url"`
Description string `mapstructure:"T" json:"description"`
Size int `mapstructure:"S" json:"size" cyclonedx:"size"`
InstalledSize int `mapstructure:"I" json:"installedSize" cyclonedx:"installedSize"`
PullDependencies string `mapstructure:"D" json:"pullDependencies" cyclonedx:"pullDependencies"`
PullChecksum string `mapstructure:"C" json:"pullChecksum" cyclonedx:"pullChecksum"`
GitCommitOfAport string `mapstructure:"c" json:"gitCommitOfApkPort" cyclonedx:"gitCommitOfApkPort"`
Files []ApkFileRecord `json:"files"`
Package string `mapstructure:"P" json:"package"`
OriginPackage string `mapstructure:"o" json:"originPackage" cyclonedx:"originPackage"`
Maintainer string `mapstructure:"m" json:"maintainer"`
Version string `mapstructure:"V" json:"version"`
License string `mapstructure:"L" json:"license"`
Architecture string `mapstructure:"A" json:"architecture"`
URL string `mapstructure:"U" json:"url"`
Description string `mapstructure:"T" json:"description"`
Size int `mapstructure:"S" json:"size" cyclonedx:"size"`
InstalledSize int `mapstructure:"I" json:"installedSize" cyclonedx:"installedSize"`
Dependencies []string `mapstructure:"D" json:"pullDependencies" cyclonedx:"pullDependencies"`
Provides []string `mapstructure:"p" json:"provides" cyclonedx:"provides"`
Checksum string `mapstructure:"C" json:"pullChecksum" cyclonedx:"pullChecksum"`
GitCommit string `mapstructure:"c" json:"gitCommitOfApkPort" cyclonedx:"gitCommitOfApkPort"`
Files []ApkFileRecord `json:"files"`
}
// ApkFileRecord represents a single file listing and metadata from a APK DB entry (which may have many of these file records).

View File

@ -66,7 +66,7 @@ func parseApkDB(_ source.FileResolver, env *generic.Environment, reader source.L
return nil, nil, fmt.Errorf("failed to parse APK DB file: %w", err)
}
return pkgs, nil, nil
return pkgs, discoverPackageDependencies(pkgs), nil
}
// parseApkDBEntry reads and parses a single pkg.ApkMetadata element from the stream, returning nil if their are no more entries.
@ -75,6 +75,10 @@ func parseApkDB(_ source.FileResolver, env *generic.Environment, reader source.L
func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) {
var entry pkg.ApkMetadata
pkgFields := make(map[string]interface{})
// We want sane defaults for collections, i.e. an empty array instead of null.
pkgFields["D"] = []string{}
pkgFields["p"] = []string{}
files := make([]pkg.ApkFileRecord, 0)
var fileRecord *pkg.ApkFileRecord
@ -92,6 +96,9 @@ func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) {
value := strings.TrimSpace(fields[1])
switch key {
case "D", "p":
entries := strings.Split(value, " ")
pkgFields[key] = entries
case "F":
currentFile := "/" + value
@ -143,7 +150,20 @@ func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) {
}
}
if err := mapstructure.Decode(pkgFields, &entry); err != nil {
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
// By default, mapstructure compares field names in a *case-insensitive* manner.
// That would be the wrong approach here, since these apk files use case
// *sensitive* field names (e.g. 'P' vs. 'p').
MatchName: func(mapKey, fieldName string) bool {
return mapKey == fieldName
},
Result: &entry,
})
if err != nil {
return nil, err
}
if err := decoder.Decode(pkgFields); err != nil {
return nil, fmt.Errorf("unable to parse APK metadata: %w", err)
}
if entry.Package == "" {
@ -174,3 +194,58 @@ func processChecksum(value string) *file.Digest {
Value: value,
}
}
func discoverPackageDependencies(pkgs []pkg.Package) (relationships []artifact.Relationship) {
// map["provides" string] -> packages that provide the "p" key
lookup := make(map[string][]pkg.Package)
// read "Provides" (p) and add as keys for lookup keys as well as package names
for _, p := range pkgs {
apkg, ok := p.Metadata.(pkg.ApkMetadata)
if !ok {
log.Warnf("cataloger failed to extract apk 'provides' metadata for package %+v", p.Name)
continue
}
lookup[p.Name] = append(lookup[p.Name], p)
for _, provides := range apkg.Provides {
k := stripVersionSpecifier(provides)
lookup[k] = append(lookup[k], p)
}
}
// read "Pull Dependencies" (D) and match with keys
for _, p := range pkgs {
apkg, ok := p.Metadata.(pkg.ApkMetadata)
if !ok {
log.Warnf("cataloger failed to extract apk dependency metadata for package %+v", p.Name)
continue
}
for _, depSpecifier := range apkg.Dependencies {
// use the lookup to find what pkg we depend on
dep := stripVersionSpecifier(depSpecifier)
for _, depPkg := range lookup[dep] {
// this is a pkg that package "p" depends on... make a relationship
relationships = append(relationships, artifact.Relationship{
From: depPkg,
To: p,
Type: artifact.DependencyOfRelationship,
})
}
}
}
return relationships
}
func splitAny(s string, seps string) []string {
splitter := func(r rune) bool {
return strings.ContainsRune(seps, r)
}
return strings.FieldsFunc(s, splitter)
}
func stripVersionSpecifier(s string) string {
// examples:
// musl>=1 --> musl
// cmd:scanelf=1.3.4-r0 --> cmd:scanelf
return splitAny(s, "<>=")[0]
}

View File

@ -6,6 +6,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -83,19 +84,20 @@ func TestSinglePackageDetails(t *testing.T) {
{
fixture: "test-fixtures/single",
expected: pkg.ApkMetadata{
Package: "musl-utils",
OriginPackage: "musl",
Version: "1.1.24-r2",
Description: "the musl c library (libc) implementation",
Maintainer: "Timo Teräs <timo.teras@iki.fi>",
License: "MIT BSD GPL2+",
Architecture: "x86_64",
URL: "https://musl.libc.org/",
Size: 37944,
InstalledSize: 151552,
PullDependencies: "scanelf so:libc.musl-x86_64.so.1",
PullChecksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=",
GitCommitOfAport: "4024cc3b29ad4c65544ad068b8f59172b5494306",
Package: "musl-utils",
OriginPackage: "musl",
Version: "1.1.24-r2",
Description: "the musl c library (libc) implementation",
Maintainer: "Timo Teräs <timo.teras@iki.fi>",
License: "MIT BSD GPL2+",
Architecture: "x86_64",
URL: "https://musl.libc.org/",
Size: 37944,
InstalledSize: 151552,
Dependencies: []string{"scanelf", "so:libc.musl-x86_64.so.1"},
Provides: []string{"cmd:getconf", "cmd:getent", "cmd:iconv", "cmd:ldconfig", "cmd:ldd"},
Checksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=",
GitCommit: "4024cc3b29ad4c65544ad068b8f59172b5494306",
Files: []pkg.ApkFileRecord{
{
Path: "/sbin",
@ -162,19 +164,20 @@ func TestSinglePackageDetails(t *testing.T) {
{
fixture: "test-fixtures/base",
expected: pkg.ApkMetadata{
Package: "alpine-baselayout",
OriginPackage: "alpine-baselayout",
Version: "3.2.0-r6",
Description: "Alpine base dir structure and init scripts",
Maintainer: "Natanael Copa <ncopa@alpinelinux.org>",
License: "GPL-2.0-only",
Architecture: "x86_64",
URL: "https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout",
Size: 19917,
InstalledSize: 409600,
PullDependencies: "/bin/sh so:libc.musl-x86_64.so.1",
PullChecksum: "Q1myMNfd7u5v5UTgNHeq1e31qTjZU=",
GitCommitOfAport: "e1c51734fa96fa4bac92e9f14a474324c67916fc",
Package: "alpine-baselayout",
OriginPackage: "alpine-baselayout",
Version: "3.2.0-r6",
Description: "Alpine base dir structure and init scripts",
Maintainer: "Natanael Copa <ncopa@alpinelinux.org>",
License: "GPL-2.0-only",
Architecture: "x86_64",
URL: "https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout",
Size: 19917,
InstalledSize: 409600,
Dependencies: []string{"/bin/sh", "so:libc.musl-x86_64.so.1"},
Provides: []string{"cmd:mkmntdirs"},
Checksum: "Q1myMNfd7u5v5UTgNHeq1e31qTjZU=",
GitCommit: "e1c51734fa96fa4bac92e9f14a474324c67916fc",
Files: []pkg.ApkFileRecord{
{
Path: "/dev",
@ -630,10 +633,9 @@ func TestSinglePackageDetails(t *testing.T) {
}
func TestMultiplePackages(t *testing.T) {
fixture := "test-fixtures/multiple"
fixtureLocationSet := source.NewLocationSet(source.NewLocation(fixture))
expected := []pkg.Package{
expectedPkgs := []pkg.Package{
{
Name: "libc-utils",
Version: "0.7.2-r0",
@ -643,20 +645,21 @@ func TestMultiplePackages(t *testing.T) {
Locations: fixtureLocationSet,
MetadataType: pkg.ApkMetadataType,
Metadata: pkg.ApkMetadata{
Package: "libc-utils",
OriginPackage: "libc-dev",
Maintainer: "Natanael Copa <ncopa@alpinelinux.org>",
Version: "0.7.2-r0",
License: "BSD",
Architecture: "x86_64",
URL: "http://alpinelinux.org",
Description: "Meta package to pull in correct libc",
Size: 1175,
InstalledSize: 4096,
PullChecksum: "Q1p78yvTLG094tHE1+dToJGbmYzQE=",
GitCommitOfAport: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479",
PullDependencies: "musl-utils",
Files: []pkg.ApkFileRecord{},
Package: "libc-utils",
OriginPackage: "libc-dev",
Maintainer: "Natanael Copa <ncopa@alpinelinux.org>",
Version: "0.7.2-r0",
License: "BSD",
Architecture: "x86_64",
URL: "http://alpinelinux.org",
Description: "Meta package to pull in correct libc",
Size: 1175,
InstalledSize: 4096,
Checksum: "Q1p78yvTLG094tHE1+dToJGbmYzQE=",
GitCommit: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479",
Dependencies: []string{"musl-utils"},
Provides: []string{},
Files: []pkg.ApkFileRecord{},
},
},
{
@ -668,19 +671,20 @@ func TestMultiplePackages(t *testing.T) {
Locations: fixtureLocationSet,
MetadataType: pkg.ApkMetadataType,
Metadata: pkg.ApkMetadata{
Package: "musl-utils",
OriginPackage: "musl",
Version: "1.1.24-r2",
Description: "the musl c library (libc) implementation",
Maintainer: "Timo Teräs <timo.teras@iki.fi>",
License: "MIT BSD GPL2+",
Architecture: "x86_64",
URL: "https://musl.libc.org/",
Size: 37944,
InstalledSize: 151552,
PullDependencies: "scanelf so:libc.musl-x86_64.so.1",
PullChecksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=",
GitCommitOfAport: "4024cc3b29ad4c65544ad068b8f59172b5494306",
Package: "musl-utils",
OriginPackage: "musl",
Version: "1.1.24-r2",
Description: "the musl c library (libc) implementation",
Maintainer: "Timo Teräs <timo.teras@iki.fi>",
License: "MIT BSD GPL2+",
Architecture: "x86_64",
URL: "https://musl.libc.org/",
Size: 37944,
InstalledSize: 151552,
GitCommit: "4024cc3b29ad4c65544ad068b8f59172b5494306",
Dependencies: []string{"scanelf", "so:libc.musl-x86_64.so.1"},
Provides: []string{"cmd:getconf", "cmd:getent", "cmd:iconv", "cmd:ldconfig", "cmd:ldd"},
Checksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=",
Files: []pkg.ApkFileRecord{
{
Path: "/sbin",
@ -746,15 +750,21 @@ func TestMultiplePackages(t *testing.T) {
},
}
// TODO: relationships are not under test
var expectedRelationships []artifact.Relationship
expectedRelationships := []artifact.Relationship{
{
From: expectedPkgs[1], // musl-utils
To: expectedPkgs[0], // libc-utils
Type: artifact.DependencyOfRelationship,
Data: nil,
},
}
env := generic.Environment{LinuxRelease: &linux.Release{
ID: "alpine",
VersionID: "3.12",
}}
pkgtest.TestFileParserWithEnv(t, fixture, parseApkDB, &env, expected, expectedRelationships)
pkgtest.TestFileParserWithEnv(t, fixture, parseApkDB, &env, expectedPkgs, expectedRelationships)
}
@ -787,3 +797,213 @@ func Test_processChecksum(t *testing.T) {
})
}
}
func Test_discoverPackageDependencies(t *testing.T) {
tests := []struct {
name string
genFn func() ([]pkg.Package, []artifact.Relationship)
}{
{
name: "has no dependency",
genFn: func() ([]pkg.Package, []artifact.Relationship) {
a := pkg.Package{
Name: "package-a",
Metadata: pkg.ApkMetadata{
Provides: []string{"a-thing"},
},
}
a.SetID()
b := pkg.Package{
Name: "package-b",
Metadata: pkg.ApkMetadata{
Provides: []string{"b-thing"},
},
}
b.SetID()
return []pkg.Package{a, b}, nil
},
},
{
name: "has 1 dependency",
genFn: func() ([]pkg.Package, []artifact.Relationship) {
a := pkg.Package{
Name: "package-a",
Metadata: pkg.ApkMetadata{
Dependencies: []string{"b-thing"},
},
}
a.SetID()
b := pkg.Package{
Name: "package-b",
Metadata: pkg.ApkMetadata{
Provides: []string{"b-thing"},
},
}
b.SetID()
return []pkg.Package{a, b}, []artifact.Relationship{
{
From: b,
To: a,
Type: artifact.DependencyOfRelationship,
},
}
},
},
{
name: "strip version specifiers",
genFn: func() ([]pkg.Package, []artifact.Relationship) {
a := pkg.Package{
Name: "package-a",
Metadata: pkg.ApkMetadata{
Dependencies: []string{"so:libc.musl-x86_64.so.1"},
},
}
a.SetID()
b := pkg.Package{
Name: "package-b",
Metadata: pkg.ApkMetadata{
Provides: []string{"so:libc.musl-x86_64.so.1=1"},
},
}
b.SetID()
return []pkg.Package{a, b}, []artifact.Relationship{
{
From: b,
To: a,
Type: artifact.DependencyOfRelationship,
},
}
},
},
{
name: "depends on package name",
genFn: func() ([]pkg.Package, []artifact.Relationship) {
a := pkg.Package{
Name: "package-a",
Metadata: pkg.ApkMetadata{
Dependencies: []string{"musl>=1.2"},
},
}
a.SetID()
b := pkg.Package{
Name: "musl",
Metadata: pkg.ApkMetadata{
Provides: []string{"so:libc.musl-x86_64.so.1=1"},
},
}
b.SetID()
return []pkg.Package{a, b}, []artifact.Relationship{
{
From: b,
To: a,
Type: artifact.DependencyOfRelationship,
},
}
},
},
{
name: "depends on package file",
genFn: func() ([]pkg.Package, []artifact.Relationship) {
a := pkg.Package{
Name: "alpine-baselayout",
Metadata: pkg.ApkMetadata{
Dependencies: []string{"/bin/sh"},
},
}
a.SetID()
b := pkg.Package{
Name: "busybox",
Metadata: pkg.ApkMetadata{
Provides: []string{"/bin/sh"},
},
}
b.SetID()
return []pkg.Package{a, b}, []artifact.Relationship{
{
From: b,
To: a,
Type: artifact.DependencyOfRelationship,
},
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pkgs, wantRelationships := tt.genFn()
gotRelationships := discoverPackageDependencies(pkgs)
d := cmp.Diff(wantRelationships, gotRelationships, cmpopts.IgnoreUnexported(pkg.Package{}, source.LocationSet{}))
if d != "" {
t.Fail()
t.Log(d)
}
})
}
}
func TestPackageDbDependenciesByParse(t *testing.T) {
tests := []struct {
fixture string
expected map[string][]string
}{
{
fixture: "test-fixtures/installed",
expected: map[string][]string{
"alpine-baselayout": {"alpine-baselayout-data", "busybox", "musl"},
"apk-tools": {"musl", "ca-certificates-bundle", "musl", "libcrypto1.1", "libssl1.1", "zlib"},
"busybox": {"musl"},
"libc-utils": {"musl-utils"},
"libcrypto1.1": {"musl"},
"libssl1.1": {"musl", "libcrypto1.1"},
"musl-utils": {"scanelf", "musl"},
"scanelf": {"musl"},
"ssl_client": {"musl", "libcrypto1.1", "libssl1.1"},
"zlib": {"musl"},
},
},
}
for _, test := range tests {
t.Run(test.fixture, func(t *testing.T) {
f, err := os.Open(test.fixture)
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, f.Close()) })
pkgs, relationships, err := parseApkDB(nil, nil, source.LocationReadCloser{
Location: source.NewLocation(test.fixture),
ReadCloser: f,
})
require.NoError(t, err)
pkgsByID := make(map[artifact.ID]pkg.Package)
for _, p := range pkgs {
p.SetID()
pkgsByID[p.ID()] = p
}
actualDependencies := make(map[string][]string)
for _, r := range relationships {
switch r.Type {
case artifact.DependencyOfRelationship:
to := pkgsByID[r.To.ID()]
from := pkgsByID[r.From.ID()]
actualDependencies[to.Name] = append(actualDependencies[to.Name], from.Name)
default:
t.Fatalf("unexpected relationship type: %+v", r.Type)
}
}
if d := cmp.Diff(test.expected, actualDependencies); d != "" {
t.Fail()
t.Log(d)
}
})
}
}

View File

@ -0,0 +1,638 @@
C:Q1v4QhLje3kWlC8DJj+ZfJTjlJRSU=
P:alpine-baselayout-data
V:3.2.0-r22
A:x86_64
S:11435
I:73728
T:Alpine base dir structure and init scripts
U:https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout
L:GPL-2.0-only
o:alpine-baselayout
m:Natanael Copa <ncopa@alpinelinux.org>
t:1655134784
c:cb70ca5c6d6db0399d2dd09189c5d57827bce5cd
r:alpine-baselayout
F:etc
R:fstab
Z:Q11Q7hNe8QpDS531guqCdrXBzoA/o=
R:group
Z:Q13K+olJg5ayzHSVNUkggZJXuB+9Y=
R:hostname
Z:Q16nVwYVXP/tChvUPdukVD2ifXOmc=
R:hosts
Z:Q1BD6zJKZTRWyqGnPi4tSfd3krsMU=
R:inittab
Z:Q1TsthbhW7QzWRe1E/NKwTOuD4pHc=
R:modules
Z:Q1toogjUipHGcMgECgPJX64SwUT1M=
R:mtab
a:0:0:777
Z:Q1kiljhXXH1LlQroHsEJIkPZg2eiw=
R:passwd
Z:Q1TchuuLUfur0izvfZQZxgN/LJhB8=
R:profile
Z:Q1F3DgXUP+jNZDknmQPPb5t9FSfDg=
R:protocols
Z:Q1omKlp3vgGq2ZqYzyD/KHNdo8rDc=
R:services
Z:Q19WLCv5ItKg4MH7RWfNRh1I7byQc=
R:shadow
a:0:42:640
Z:Q1ltrPIAW2zHeDiajsex2Bdmq3uqA=
R:shells
Z:Q1ojm2YdpCJ6B/apGDaZ/Sdb2xJkA=
R:sysctl.conf
Z:Q14upz3tfnNxZkIEsUhWn7Xoiw96g=
C:Q1aCu0LmUDoAFSOX49uHvkYC1WasQ=
P:musl
V:1.2.3-r0
A:x86_64
S:383304
I:622592
T:the musl c library (libc) implementation
U:https://musl.libc.org/
L:MIT
o:musl
m:Timo Teräs <timo.teras@iki.fi>
t:1649396308
c:ee13d43a53938d8a04ba787b9423f3270a3c14a7
p:so:libc.musl-x86_64.so.1=1
F:lib
R:ld-musl-x86_64.so.1
a:0:0:755
Z:Q1ZZqflKEvStJz4SXV0SDMi3wOtM0=
R:libc.musl-x86_64.so.1
a:0:0:777
Z:Q17yJ3JFNypA4mxhJJr0ou6CzsJVI=
C:Q1iZ+C2JJdBlm2KKtAOkSkM7zZegY=
P:busybox
V:1.35.0-r17
A:x86_64
S:507831
I:962560
T:Size optimized toolbox of many common UNIX utilities
U:https://busybox.net/
L:GPL-2.0-only
o:busybox
m:Sören Tempel <soeren+alpine@soeren-tempel.net>
t:1659366884
c:2bf6ec48e526113f87216683cd341a78af5f0b3f
D:so:libc.musl-x86_64.so.1
p:/bin/sh cmd:busybox=1.35.0-r17 cmd:sh=1.35.0-r17
r:busybox-initscripts
F:bin
R:busybox
a:0:0:755
Z:Q1WUwBY0eOGgzgVxTZxJBZPyQUicI=
R:sh
a:0:0:777
Z:Q1pcfTfDNEbNKQc2s1tia7da05M8Q=
F:etc
R:securetty
Z:Q1mB95Hq2NUTZ599RDiSsj9w5FrOU=
R:udhcpd.conf
Z:Q1EgLFjj67ou3eMqp4m3r2ZjnQ7QU=
F:etc/logrotate.d
R:acpid
Z:Q1TylyCINVmnS+A/Tead4vZhE7Bks=
F:etc/network
F:etc/network/if-down.d
F:etc/network/if-post-down.d
F:etc/network/if-post-up.d
F:etc/network/if-pre-down.d
F:etc/network/if-pre-up.d
F:etc/network/if-up.d
R:dad
a:0:0:775
Z:Q1ORf+lPRKuYgdkBBcKoevR1t60Q4=
F:sbin
F:tmp
M:0:0:1777
F:usr
F:usr/sbin
F:usr/share
F:usr/share/udhcpc
R:default.script
a:0:0:755
Z:Q1t9vir/ZrX3nbSIYT9BDLWZenkVQ=
F:var
F:var/cache
F:var/cache/misc
F:var/lib
F:var/lib/udhcpd
C:Q1l6/nM0K+cyVdqNfgkp1/c6Ylzk0=
P:alpine-baselayout
V:3.2.0-r22
A:x86_64
S:11126
I:348160
T:Alpine base dir structure and init scripts
U:https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout
L:GPL-2.0-only
o:alpine-baselayout
m:Natanael Copa <ncopa@alpinelinux.org>
t:1655134784
c:cb70ca5c6d6db0399d2dd09189c5d57827bce5cd
D:alpine-baselayout-data=3.2.0-r22 /bin/sh so:libc.musl-x86_64.so.1
p:cmd:mkmntdirs=3.2.0-r22
F:dev
F:dev/pts
F:dev/shm
F:etc
R:motd
Z:Q1XmduVVNURHQ27TvYp1Lr5TMtFcA=
F:etc/apk
F:etc/conf.d
F:etc/crontabs
R:root
a:0:0:600
Z:Q1vfk1apUWI4yLJGhhNRd0kJixfvY=
F:etc/init.d
F:etc/modprobe.d
R:aliases.conf
Z:Q1WUbh6TBYNVK7e4Y+uUvLs/7viqk=
R:blacklist.conf
Z:Q14TdgFHkTdt3uQC+NBtrntOnm9n4=
R:i386.conf
Z:Q1pnay/njn6ol9cCssL7KiZZ8etlc=
R:kms.conf
Z:Q1ynbLn3GYDpvajba/ldp1niayeog=
F:etc/modules-load.d
F:etc/network
F:etc/network/if-down.d
F:etc/network/if-post-down.d
F:etc/network/if-pre-up.d
F:etc/network/if-up.d
F:etc/opt
F:etc/periodic
F:etc/periodic/15min
F:etc/periodic/daily
F:etc/periodic/hourly
F:etc/periodic/monthly
F:etc/periodic/weekly
F:etc/profile.d
R:README
Z:Q135OWsCzzvnB2fmFx62kbqm1Ax1k=
R:color_prompt.sh.disabled
Z:Q11XM9mde1Z29tWMGaOkeovD/m4uU=
R:locale.sh
Z:Q1S8j+WW71mWxfVy8ythqU7HUVoBw=
F:etc/sysctl.d
F:home
F:lib
F:lib/firmware
F:lib/mdev
F:lib/modules-load.d
F:lib/sysctl.d
R:00-alpine.conf
Z:Q1HpElzW1xEgmKfERtTy7oommnq6c=
F:media
F:media/cdrom
F:media/floppy
F:media/usb
F:mnt
F:opt
F:proc
F:root
M:0:0:700
F:run
F:sbin
R:mkmntdirs
a:0:0:755
Z:Q1+f8Hjd+dkHS03O6ZZaIw7mb8nLM=
F:srv
F:sys
F:tmp
M:0:0:1777
F:usr
F:usr/lib
F:usr/lib/modules-load.d
F:usr/local
F:usr/local/bin
F:usr/local/lib
F:usr/local/share
F:usr/sbin
F:usr/share
F:usr/share/man
F:usr/share/misc
F:var
R:run
a:0:0:777
Z:Q11/SNZz/8cK2dSKK+cJpVrZIuF4Q=
F:var/cache
F:var/cache/misc
F:var/empty
M:0:0:555
F:var/lib
F:var/lib/misc
F:var/local
F:var/lock
F:var/lock/subsys
F:var/log
F:var/mail
F:var/opt
F:var/spool
R:mail
a:0:0:777
Z:Q1dzbdazYZA2nTzSIG3YyNw7d4Juc=
F:var/spool/cron
R:crontabs
a:0:0:777
Z:Q1OFZt+ZMp7j0Gny0rqSKuWJyqYmA=
F:var/tmp
M:0:0:1777
C:Q1FBfIjtsEmvuqoNXpShXDcm/mjzE=
P:alpine-keys
V:2.4-r1
A:x86_64
S:13359
I:159744
T:Public keys for Alpine Linux packages
U:https://alpinelinux.org
L:MIT
o:alpine-keys
m:Natanael Copa <ncopa@alpinelinux.org>
t:1634579657
c:aab68f8c9ab434a46710de8e12fb3206e2930a59
r:alpine-base
F:etc
F:etc/apk
F:etc/apk/keys
R:alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
Z:Q1OvCFSO94z97c80mIDCxqGkh2Og4=
R:alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub
Z:Q1v7YWZYzAWoclaLDI45jEguI7YN0=
R:alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub
Z:Q1NnGuDsdQOx4ZNYfB3N97eLyGPkI=
R:alpine-devel@lists.alpinelinux.org-6165ee59.rsa.pub
Z:Q1lZlTESNrelWTNkL/oQzmAU8a99A=
R:alpine-devel@lists.alpinelinux.org-61666e3f.rsa.pub
Z:Q1WNW6Sy87HpJ3IdemQy8pju33Kms=
F:usr
F:usr/share
F:usr/share/apk
F:usr/share/apk/keys
R:alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
Z:Q1OvCFSO94z97c80mIDCxqGkh2Og4=
R:alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub
Z:Q1v7YWZYzAWoclaLDI45jEguI7YN0=
R:alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub
Z:Q1BTqS+H/UUyhQuzHwiBl47+BTKuU=
R:alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub
Z:Q1NnGuDsdQOx4ZNYfB3N97eLyGPkI=
R:alpine-devel@lists.alpinelinux.org-58199dcc.rsa.pub
Z:Q1Oaxdcsa6AYoPdLi0U4lO3J2we18=
R:alpine-devel@lists.alpinelinux.org-58cbb476.rsa.pub
Z:Q1yPq+su65ksNox3uXB+DR7P18+QU=
R:alpine-devel@lists.alpinelinux.org-58e4f17d.rsa.pub
Z:Q1MpZDNX0LeLHvSOwVUyXiXx11NN0=
R:alpine-devel@lists.alpinelinux.org-5e69ca50.rsa.pub
Z:Q1glCQ/eJbvA5xqcswdjFrWv5Fnk0=
R:alpine-devel@lists.alpinelinux.org-60ac2099.rsa.pub
Z:Q1XUdDEoNTtjlvrS+iunk6ziFgIpU=
R:alpine-devel@lists.alpinelinux.org-6165ee59.rsa.pub
Z:Q1lZlTESNrelWTNkL/oQzmAU8a99A=
R:alpine-devel@lists.alpinelinux.org-61666e3f.rsa.pub
Z:Q1WNW6Sy87HpJ3IdemQy8pju33Kms=
R:alpine-devel@lists.alpinelinux.org-616a9724.rsa.pub
Z:Q1I9Dy6hryacL2YWXg+KlE6WvwEd4=
R:alpine-devel@lists.alpinelinux.org-616abc23.rsa.pub
Z:Q1NSnsgmcMbU4g7j5JaNs0tVHpHVA=
R:alpine-devel@lists.alpinelinux.org-616ac3bc.rsa.pub
Z:Q1VaMBBk4Rxv6boPLKF+I085Q8y2E=
R:alpine-devel@lists.alpinelinux.org-616adfeb.rsa.pub
Z:Q13hJBMHAUquPbp5jpAPFjQI2Y1vQ=
R:alpine-devel@lists.alpinelinux.org-616ae350.rsa.pub
Z:Q1V/a5P9pKRJb6tihE3e8O6xaPgLU=
R:alpine-devel@lists.alpinelinux.org-616db30d.rsa.pub
Z:Q13wLJrcKQajql5a1p9Q45U+ZXENA=
F:usr/share/apk/keys/aarch64
R:alpine-devel@lists.alpinelinux.org-58199dcc.rsa.pub
a:0:0:777
Z:Q17j9nWJkQ+wfIuVQzIFrmFZ7fSOc=
R:alpine-devel@lists.alpinelinux.org-616ae350.rsa.pub
a:0:0:777
Z:Q1snr+Q1UbfHyCr/cmmtVvMIS7SGs=
F:usr/share/apk/keys/armhf
R:alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub
a:0:0:777
Z:Q1U9QtsdN+rYZ9Zh76EfXy00JZHMg=
R:alpine-devel@lists.alpinelinux.org-616a9724.rsa.pub
a:0:0:777
Z:Q1bC+AdQ0qWBTmefXiI0PvmYOJoVQ=
F:usr/share/apk/keys/armv7
R:alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub
a:0:0:777
Z:Q1U9QtsdN+rYZ9Zh76EfXy00JZHMg=
R:alpine-devel@lists.alpinelinux.org-616adfeb.rsa.pub
a:0:0:777
Z:Q1xbIVu7ScwqGHxXGwI22aSe5OdUY=
F:usr/share/apk/keys/mips64
R:alpine-devel@lists.alpinelinux.org-5e69ca50.rsa.pub
a:0:0:777
Z:Q1hCZdFx+LvzbLtPs753je78gEEBQ=
F:usr/share/apk/keys/ppc64le
R:alpine-devel@lists.alpinelinux.org-58cbb476.rsa.pub
a:0:0:777
Z:Q1t21dhCLbTJmAHXSCeOMq/2vfSgo=
R:alpine-devel@lists.alpinelinux.org-616abc23.rsa.pub
a:0:0:777
Z:Q1PS9zNIPJanC8qcsc5qarEWqhV5Q=
F:usr/share/apk/keys/riscv64
R:alpine-devel@lists.alpinelinux.org-60ac2099.rsa.pub
a:0:0:777
Z:Q1NVPbZavaXpsItFwQYDWbpor7yYE=
R:alpine-devel@lists.alpinelinux.org-616db30d.rsa.pub
a:0:0:777
Z:Q1U6tfuKRy5J8C6iaKPMZaT/e8tbA=
F:usr/share/apk/keys/s390x
R:alpine-devel@lists.alpinelinux.org-58e4f17d.rsa.pub
a:0:0:777
Z:Q1sjbV2r2w0Ih2vwdzC4Jq6UI7cMQ=
R:alpine-devel@lists.alpinelinux.org-616ac3bc.rsa.pub
a:0:0:777
Z:Q1l09xa7RnbOIC1dI9FqbaCfS/GXY=
F:usr/share/apk/keys/x86
R:alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
a:0:0:777
Z:Q1Ii51i7Nrc4uft14HhqugaUqdH64=
R:alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub
a:0:0:777
Z:Q1Y49eVxhpvftbQ3yAdvlLfcrPLTU=
R:alpine-devel@lists.alpinelinux.org-61666e3f.rsa.pub
a:0:0:777
Z:Q1HjdvcVkpBZzr1aSe3p7oQfAtm/E=
F:usr/share/apk/keys/x86_64
R:alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
a:0:0:777
Z:Q1Ii51i7Nrc4uft14HhqugaUqdH64=
R:alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub
a:0:0:777
Z:Q1AUFY+fwSBTcrYetjT7NHvafrSQc=
R:alpine-devel@lists.alpinelinux.org-6165ee59.rsa.pub
a:0:0:777
Z:Q1qKA23VzMUDle+Dqnrr5Kz+Xvty4=
C:Q1huqjigIP7ZNHBueDUmNnT6PpToI=
P:ca-certificates-bundle
V:20220614-r0
A:x86_64
S:125920
I:233472
T:Pre generated bundle of Mozilla certificates
U:https://www.mozilla.org/en-US/about/governance/policies/security-group/certs/
L:MPL-2.0 AND MIT
o:ca-certificates
m:Natanael Copa <ncopa@alpinelinux.org>
t:1659254961
c:bb51fa7743320ac61f76e181cca84daa9977573e
p:ca-certificates-cacert=20220614-r0
r:libressl2.7-libcrypto
F:etc
F:etc/ssl
R:cert.pem
a:0:0:777
Z:Q1Nj6gTBdkZpTFW/obJGdpfvK0StA=
F:etc/ssl/certs
R:ca-certificates.crt
Z:Q1D8ljYj7pXsRq4d/eHGNYB0GY1+I=
C:Q1rd80DWg+fcm+GFn06ahfUUPUshw=
P:libcrypto1.1
V:1.1.1q-r0
A:x86_64
S:1212577
I:2772992
T:Crypto library from openssl
U:https://www.openssl.org/
L:OpenSSL
o:openssl
m:Timo Teras <timo.teras@iki.fi>
t:1657033577
c:26153b65138c876d57e81750f6de6baab6d5bd5b
D:so:libc.musl-x86_64.so.1
p:so:libcrypto.so.1.1=1.1
r:libressl2.7-libcrypto
F:etc
F:etc/ssl
R:ct_log_list.cnf
Z:Q1olh8TpdAi2QnTl4FK3TjdUiSwTo=
R:ct_log_list.cnf.dist
Z:Q1olh8TpdAi2QnTl4FK3TjdUiSwTo=
R:openssl.cnf
Z:Q1wGuxVEOK9iGLj1i8D3BSBnT7MJA=
R:openssl.cnf.dist
Z:Q1wGuxVEOK9iGLj1i8D3BSBnT7MJA=
F:etc/ssl/certs
F:etc/ssl/misc
R:CA.pl
a:0:0:755
Z:Q1IACevKhK93GYBHp96Ie26jgZ17s=
R:tsget
a:0:0:777
Z:Q13NVgfr7dQUuGYxur0tNalH6EIjU=
R:tsget.pl
a:0:0:755
Z:Q15sBrpDGKgjg82+bFLL8ivnu5pbQ=
F:etc/ssl/private
F:lib
R:libcrypto.so.1.1
a:0:0:755
Z:Q1f/TrTwFtSlD1k639L+FfsTkJWPY=
F:usr
F:usr/lib
R:libcrypto.so.1.1
a:0:0:777
Z:Q1T2si+c7ts7sgDxQYve4B3i1Dgo0=
F:usr/lib/engines-1.1
R:afalg.so
a:0:0:755
Z:Q1Oljrwcq5h1sKPXcImsYYWLqm9SA=
R:capi.so
a:0:0:755
Z:Q1Xtf9a1EQ1VWfygx1oNhMvNoNZzw=
R:padlock.so
a:0:0:755
Z:Q1ttkhyM+fT6wkUcV9zgXXTTF7VNo=
C:Q1ciplPwPAKDa19jkbxYjiiv+G5Es=
P:libssl1.1
V:1.1.1q-r0
A:x86_64
S:213294
I:540672
T:SSL shared libraries
U:https://www.openssl.org/
L:OpenSSL
o:openssl
m:Timo Teras <timo.teras@iki.fi>
t:1657033577
c:26153b65138c876d57e81750f6de6baab6d5bd5b
D:so:libc.musl-x86_64.so.1 so:libcrypto.so.1.1
p:so:libssl.so.1.1=1.1
r:libressl
F:lib
R:libssl.so.1.1
a:0:0:755
Z:Q1/on1tWApiZJE4XvUyE6MTFO2MY0=
F:usr
F:usr/lib
R:libssl.so.1.1
a:0:0:777
Z:Q18j35pe3yp6HOgMih1wlGP1/mm2c=
C:Q1KWJXawaNPiINHfdzCg/FrEmiAaU=
P:ssl_client
V:1.35.0-r17
A:x86_64
S:5004
I:28672
T:EXternal ssl_client for busybox wget
U:https://busybox.net/
L:GPL-2.0-only
o:busybox
m:Sören Tempel <soeren+alpine@soeren-tempel.net>
t:1659366884
c:2bf6ec48e526113f87216683cd341a78af5f0b3f
D:so:libc.musl-x86_64.so.1 so:libcrypto.so.1.1 so:libssl.so.1.1
p:cmd:ssl_client=1.35.0-r17
i:busybox=1.35.0-r17 libssl1.1
r:busybox-initscripts
F:usr
F:usr/bin
R:ssl_client
a:0:0:755
Z:Q1C6qA8RFt5eagesbaqu4plc6Ctyc=
C:Q1Ekuqm/0CPywDCKEbEwhsPCw+z9E=
P:zlib
V:1.2.12-r3
A:x86_64
S:53346
I:110592
T:A compression/decompression Library
U:https://zlib.net/
L:Zlib
o:zlib
m:Natanael Copa <ncopa@alpinelinux.org>
t:1660030129
c:57ce38bde7ce42964b664c137935cf2de803ac44
D:so:libc.musl-x86_64.so.1
p:so:libz.so.1=1.2.12
F:lib
R:libz.so.1
a:0:0:777
Z:Q1+aBjyJ7dmLatVkyqCNnAChlDZh8=
R:libz.so.1.2.12
a:0:0:755
Z:Q1x/qx/7zlM20k7fLfVee7A4WLOC8=
C:Q1VFFFWMKjB9aRkehIATc5kwgAhlU=
P:apk-tools
V:2.12.9-r3
A:x86_64
S:120745
I:307200
T:Alpine Package Keeper - package manager for alpine
U:https://gitlab.alpinelinux.org/alpine/apk-tools
L:GPL-2.0-only
o:apk-tools
m:Natanael Copa <ncopa@alpinelinux.org>
t:1652592000
c:34d90ac8388e88126893f5d27ea35d304e65e5ab
D:musl>=1.2 ca-certificates-bundle so:libc.musl-x86_64.so.1 so:libcrypto.so.1.1 so:libssl.so.1.1 so:libz.so.1
p:so:libapk.so.3.12.0=3.12.0 cmd:apk=2.12.9-r3
F:etc
F:etc/apk
F:etc/apk/keys
F:etc/apk/protected_paths.d
F:lib
R:libapk.so.3.12.0
a:0:0:755
Z:Q1kVeagJvcGMIKp8ijGOxaZD08ONs=
F:sbin
R:apk
a:0:0:755
Z:Q1P1oUBG/VMMhnndf2fBXsZXBjHVE=
F:var
F:var/cache
F:var/cache/misc
F:var/lib
F:var/lib/apk
C:Q1Gcqe+ND8DFOlhM3R0o5KyZjR2oE=
P:scanelf
V:1.3.4-r0
A:x86_64
S:36745
I:94208
T:Scan ELF binaries for stuff
U:https://wiki.gentoo.org/wiki/Hardened/PaX_Utilities
L:GPL-2.0-only
o:pax-utils
m:Natanael Copa <ncopa@alpinelinux.org>
t:1651005390
c:d7ae612a3cc5f827289d915783b4cbf8c7207947
D:so:libc.musl-x86_64.so.1
p:cmd:scanelf=1.3.4-r0
r:pax-utils
F:usr
F:usr/bin
R:scanelf
a:0:0:755
Z:Q1YPb72qHJJvTH6mJkN9DuExFQQh8=
C:Q1VVfxM3uSO0X38HWpj1LN0E61fxo=
P:musl-utils
V:1.2.3-r0
A:x86_64
S:36938
I:135168
T:the musl c library (libc) implementation
U:https://musl.libc.org/
L:MIT BSD GPL2+
o:musl
m:Timo Teräs <timo.teras@iki.fi>
t:1649396308
c:ee13d43a53938d8a04ba787b9423f3270a3c14a7
D:scanelf so:libc.musl-x86_64.so.1
p:cmd:getconf=1.2.3-r0 cmd:getent=1.2.3-r0 cmd:iconv=1.2.3-r0 cmd:ldconfig=1.2.3-r0 cmd:ldd=1.2.3-r0
r:libiconv
F:sbin
R:ldconfig
a:0:0:755
Z:Q1Kja2+POZKxEkUOZqwSjC6kmaED4=
F:usr
F:usr/bin
R:getconf
a:0:0:755
Z:Q1hRQA0bFX/Ywt3mbD6NpV9BIbPrU=
R:getent
a:0:0:755
Z:Q1khbUz6GBU8iiQ3oV6Ln2hlXf4/0=
R:iconv
a:0:0:755
Z:Q1H1QpYQDkdYIK2LLGv3m6qjpLyAY=
R:ldd
a:0:0:755
Z:Q1yFAhGggmL7ERgbIA7KQxyTzf3ks=
C:Q1O4GFJRvHz95tPjO84qpEvkNVwDw=
P:libc-utils
V:0.7.2-r3
A:x86_64
S:1480
I:4096
T:Meta package to pull in correct libc
U:https://alpinelinux.org
L:BSD-2-Clause AND BSD-3-Clause
o:libc-dev
m:Natanael Copa <ncopa@alpinelinux.org>
t:1585632275
c:60424133be2e79bbfeff3d58147a22886f817ce2
D:musl-utils

View File

@ -36,7 +36,7 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
{
formatOption: syftjson.ID,
redactor: func(in []byte) []byte {
in = regexp.MustCompile("\"(id|parent)\": \"[^\"]+\",").ReplaceAll(in, []byte{})
// no redactions necessary
return in
},
json: true,
@ -44,7 +44,9 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
{
formatOption: cyclonedxjson.ID,
redactor: func(in []byte) []byte {
in = regexp.MustCompile("\"(timestamp|serialNumber|bom-ref)\": \"[^\"]+\",").ReplaceAll(in, []byte{})
// unstable values
in = regexp.MustCompile(`"(timestamp|serialNumber|bom-ref)": "[^"]+",`).ReplaceAll(in, []byte{})
return in
},
json: true,
@ -52,8 +54,10 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
{
formatOption: cyclonedxxml.ID,
redactor: func(in []byte) []byte {
in = regexp.MustCompile("(serialNumber|bom-ref)=\"[^\"]+\"").ReplaceAll(in, []byte{})
in = regexp.MustCompile("<timestamp>[^<]+</timestamp>").ReplaceAll(in, []byte{})
// unstable values
in = regexp.MustCompile(`(serialNumber|bom-ref)="[^"]+"`).ReplaceAll(in, []byte{})
in = regexp.MustCompile(`<timestamp>[^<]+</timestamp>`).ReplaceAll(in, []byte{})
return in
},
},