feat: detect older bitnami img packages (#4532)

Signed-off-by: Rez Moss <hi@rezmoss.com>
This commit is contained in:
Rez Moss 2026-01-07 10:07:33 -05:00 committed by GitHub
parent ed339e4fed
commit 7f1d57d06f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 294 additions and 0 deletions

View File

@ -13,6 +13,35 @@ catalogers:
- installed
- package
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
detector: # AUTO-GENERATED
method: glob # AUTO-GENERATED

View File

@ -23,6 +23,9 @@ func NewCataloger() pkg.Cataloger {
return generic.NewCataloger(catalogerName).
WithParserByGlobs(parseSBOM,
"/opt/bitnami/**/.spdx-*.spdx",
).
WithParserByGlobs(parseComponentsJSON,
"/opt/bitnami/.bitnami_components.json",
)
}

View File

@ -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 {
name string
fixture string
@ -489,6 +592,20 @@ func TestBitnamiCataloger(t *testing.T) {
wantPkgs: []pkg.Package{redisMainPkg},
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 {

View 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:]
}

View File

@ -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"
}
}

View File

@ -0,0 +1,8 @@
{
"postgresql": {
"arch": "amd64",
"distro": "debian-11",
"type": "NAMI",
"version": "11.22.0-4"
}
}