mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 02:26:42 +01:00
feat: detect older bitnami img packages (#4532)
Signed-off-by: Rez Moss <hi@rezmoss.com>
This commit is contained in:
parent
ed339e4fed
commit
7f1d57d06f
@ -13,6 +13,35 @@ catalogers:
|
|||||||
- installed
|
- installed
|
||||||
- package
|
- package
|
||||||
parsers: # AUTO-GENERATED structure
|
parsers: # AUTO-GENERATED structure
|
||||||
|
- function: parseComponentsJSON
|
||||||
|
detector: # AUTO-GENERATED
|
||||||
|
method: glob # AUTO-GENERATED
|
||||||
|
criteria: # AUTO-GENERATED
|
||||||
|
- /opt/bitnami/.bitnami_components.json
|
||||||
|
metadata_types: # AUTO-GENERATED
|
||||||
|
- pkg.BitnamiSBOMEntry
|
||||||
|
package_types: # AUTO-GENERATED
|
||||||
|
- bitnami
|
||||||
|
json_schema_types: # AUTO-GENERATED
|
||||||
|
- BitnamiSbomEntry
|
||||||
|
capabilities: # MANUAL - preserved across regeneration
|
||||||
|
- name: license
|
||||||
|
default: false
|
||||||
|
comment: legacy components.json format does not include license information
|
||||||
|
- name: dependency.depth
|
||||||
|
default: []
|
||||||
|
comment: legacy format has no dependency relationships
|
||||||
|
- name: dependency.edges
|
||||||
|
default: ""
|
||||||
|
- name: dependency.kinds
|
||||||
|
default: []
|
||||||
|
- name: package_manager.files.listing
|
||||||
|
default: false
|
||||||
|
- name: package_manager.files.digests
|
||||||
|
default: false
|
||||||
|
- name: package_manager.package_integrity_hash
|
||||||
|
default: false
|
||||||
|
comment: digest field exists but is not captured in metadata
|
||||||
- function: parseSBOM
|
- function: parseSBOM
|
||||||
detector: # AUTO-GENERATED
|
detector: # AUTO-GENERATED
|
||||||
method: glob # AUTO-GENERATED
|
method: glob # AUTO-GENERATED
|
||||||
|
|||||||
@ -23,6 +23,9 @@ func NewCataloger() pkg.Cataloger {
|
|||||||
return generic.NewCataloger(catalogerName).
|
return generic.NewCataloger(catalogerName).
|
||||||
WithParserByGlobs(parseSBOM,
|
WithParserByGlobs(parseSBOM,
|
||||||
"/opt/bitnami/**/.spdx-*.spdx",
|
"/opt/bitnami/**/.spdx-*.spdx",
|
||||||
|
).
|
||||||
|
WithParserByGlobs(parseComponentsJSON,
|
||||||
|
"/opt/bitnami/.bitnami_components.json",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -448,6 +448,109 @@ func TestBitnamiCataloger(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongodbComponentsPkgs := []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "gosu",
|
||||||
|
Version: "1.14.0-1",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/.bitnami_components.json")),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/gosu@1.14.0-1?arch=amd64&distro=debian-10",
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "gosu",
|
||||||
|
Version: "1.14.0",
|
||||||
|
Revision: "1",
|
||||||
|
Architecture: "amd64",
|
||||||
|
Distro: "debian-10",
|
||||||
|
Path: "opt/bitnami/gosu",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "mongodb",
|
||||||
|
Version: "4.4.11-2",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/.bitnami_components.json")),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/mongodb@4.4.11-2?arch=amd64&distro=debian-10",
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "mongodb",
|
||||||
|
Version: "4.4.11",
|
||||||
|
Revision: "2",
|
||||||
|
Architecture: "amd64",
|
||||||
|
Distro: "debian-10",
|
||||||
|
Path: "opt/bitnami/mongodb",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "render-template",
|
||||||
|
Version: "1.0.1-5",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/.bitnami_components.json")),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/render-template@1.0.1-5?arch=amd64&distro=debian-10",
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "render-template",
|
||||||
|
Version: "1.0.1",
|
||||||
|
Revision: "5",
|
||||||
|
Architecture: "amd64",
|
||||||
|
Distro: "debian-10",
|
||||||
|
Path: "opt/bitnami/render-template",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "wait-for-port",
|
||||||
|
Version: "1.0.1-5",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/.bitnami_components.json")),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/wait-for-port@1.0.1-5?arch=amd64&distro=debian-10",
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "wait-for-port",
|
||||||
|
Version: "1.0.1",
|
||||||
|
Revision: "5",
|
||||||
|
Architecture: "amd64",
|
||||||
|
Distro: "debian-10",
|
||||||
|
Path: "opt/bitnami/wait-for-port",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "yq",
|
||||||
|
Version: "4.16.2-2",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/.bitnami_components.json")),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/yq@4.16.2-2?arch=amd64&distro=debian-10",
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "yq",
|
||||||
|
Version: "4.16.2",
|
||||||
|
Revision: "2",
|
||||||
|
Architecture: "amd64",
|
||||||
|
Distro: "debian-10",
|
||||||
|
Path: "opt/bitnami/yq",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pkg.Sort(mongodbComponentsPkgs)
|
||||||
|
|
||||||
|
postgresqlComponentsPkgs := []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "postgresql",
|
||||||
|
Version: "11.22.0-4",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/.bitnami_components.json")),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/postgresql@11.22.0-4?arch=amd64&distro=debian-11",
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "postgresql",
|
||||||
|
Version: "11.22.0",
|
||||||
|
Revision: "4",
|
||||||
|
Architecture: "amd64",
|
||||||
|
Distro: "debian-11",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fixture string
|
fixture string
|
||||||
@ -489,6 +592,20 @@ func TestBitnamiCataloger(t *testing.T) {
|
|||||||
wantPkgs: []pkg.Package{redisMainPkg},
|
wantPkgs: []pkg.Package{redisMainPkg},
|
||||||
wantRelationships: nil,
|
wantRelationships: nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "parse legacy .bitnami_components.json (MongoDB with multiple components)",
|
||||||
|
fixture: "test-fixtures/components-json-mongodb",
|
||||||
|
wantPkgs: mongodbComponentsPkgs,
|
||||||
|
wantRelationships: nil,
|
||||||
|
wantErr: require.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "parse legacy .bitnami_components.json (PostgreSQL single component, no digest)",
|
||||||
|
fixture: "test-fixtures/components-json-postgresql",
|
||||||
|
wantPkgs: postgresqlComponentsPkgs,
|
||||||
|
wantRelationships: nil,
|
||||||
|
wantErr: require.NoError,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|||||||
100
syft/pkg/cataloger/bitnami/parse_components.go
Normal file
100
syft/pkg/cataloger/bitnami/parse_components.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package bitnami
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/packageurl-go"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
type componentEntry struct {
|
||||||
|
Arch string `json:"arch"`
|
||||||
|
Digest string `json:"digest,omitempty"`
|
||||||
|
Distro string `json:"distro"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseComponentsJSON(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
var components map[string]componentEntry
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(reader)
|
||||||
|
if err := decoder.Decode(&components); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to parse .bitnami_components.json: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
|
||||||
|
names := make([]string, 0, len(components))
|
||||||
|
for name := range components {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
entry := components[name]
|
||||||
|
|
||||||
|
version, revision := parseVersionRevision(entry.Version)
|
||||||
|
|
||||||
|
var qualifiers []packageurl.Qualifier
|
||||||
|
if entry.Arch != "" {
|
||||||
|
qualifiers = append(qualifiers, packageurl.Qualifier{Key: "arch", Value: entry.Arch})
|
||||||
|
}
|
||||||
|
if entry.Distro != "" {
|
||||||
|
qualifiers = append(qualifiers, packageurl.Qualifier{Key: "distro", Value: entry.Distro})
|
||||||
|
}
|
||||||
|
|
||||||
|
purl := packageurl.NewPackageURL(
|
||||||
|
"bitnami",
|
||||||
|
"",
|
||||||
|
name,
|
||||||
|
entry.Version,
|
||||||
|
qualifiers,
|
||||||
|
"",
|
||||||
|
).String()
|
||||||
|
|
||||||
|
metadata := &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: name,
|
||||||
|
Version: version,
|
||||||
|
Revision: revision,
|
||||||
|
Architecture: entry.Arch,
|
||||||
|
Distro: entry.Distro,
|
||||||
|
Path: filepath.Join(filepath.Dir(reader.RealPath), name),
|
||||||
|
}
|
||||||
|
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: name,
|
||||||
|
Version: entry.Version,
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: purl,
|
||||||
|
Locations: file.NewLocationSet(
|
||||||
|
reader.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
),
|
||||||
|
Metadata: metadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetID()
|
||||||
|
pkgs = append(pkgs, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// seems legacy format doesnt have relation between pkgs
|
||||||
|
return pkgs, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseVersionRevision(fullVersion string) (version, revision string) {
|
||||||
|
lastHyphen := strings.LastIndex(fullVersion, "-")
|
||||||
|
if lastHyphen == -1 {
|
||||||
|
return fullVersion, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fullVersion[:lastHyphen], fullVersion[lastHyphen+1:]
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"gosu": {
|
||||||
|
"arch": "amd64",
|
||||||
|
"digest": "16f1a317859b06ae82e816b30f98f28b4707d18fe6cc3881bff535192a7715dc",
|
||||||
|
"distro": "debian-10",
|
||||||
|
"type": "NAMI",
|
||||||
|
"version": "1.14.0-1"
|
||||||
|
},
|
||||||
|
"mongodb": {
|
||||||
|
"arch": "amd64",
|
||||||
|
"digest": "d21fc890385eae0aaa394ce6491ef304d28a5cc43f860def6badee401fe55bc5",
|
||||||
|
"distro": "debian-10",
|
||||||
|
"type": "NAMI",
|
||||||
|
"version": "4.4.11-2"
|
||||||
|
},
|
||||||
|
"render-template": {
|
||||||
|
"arch": "amd64",
|
||||||
|
"digest": "9e312b4a7e16a55d08e67c4fd69c91000e4dcc4af149d59915c49375b83852af",
|
||||||
|
"distro": "debian-10",
|
||||||
|
"type": "NAMI",
|
||||||
|
"version": "1.0.1-5"
|
||||||
|
},
|
||||||
|
"wait-for-port": {
|
||||||
|
"arch": "amd64",
|
||||||
|
"digest": "1e34030c18f0ec2467fa5f1b1fbad24add217f671c3a61628f7b8671391f9676",
|
||||||
|
"distro": "debian-10",
|
||||||
|
"type": "NAMI",
|
||||||
|
"version": "1.0.1-5"
|
||||||
|
},
|
||||||
|
"yq": {
|
||||||
|
"arch": "amd64",
|
||||||
|
"digest": "1c135708aaa8cb69936471de63563de08e97b7d0bfb4126d41b54a149557c5c0",
|
||||||
|
"distro": "debian-10",
|
||||||
|
"type": "NAMI",
|
||||||
|
"version": "4.16.2-2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"postgresql": {
|
||||||
|
"arch": "amd64",
|
||||||
|
"distro": "debian-11",
|
||||||
|
"type": "NAMI",
|
||||||
|
"version": "11.22.0-4"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user