Skip to content

Move DPKG PURL generation into the PURL gen lib. #752

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

Merged
merged 1 commit into from
May 19, 2025
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 binary/proto/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import (
"github.com/google/osv-scalibr/extractor/filesystem/misc/vscodeextensions"
"github.com/google/osv-scalibr/extractor/filesystem/os/apk"
"github.com/google/osv-scalibr/extractor/filesystem/os/cos"
"github.com/google/osv-scalibr/extractor/filesystem/os/dpkg"
dpkgmeta "github.com/google/osv-scalibr/extractor/filesystem/os/dpkg/metadata"
"github.com/google/osv-scalibr/extractor/filesystem/os/flatpak"
"github.com/google/osv-scalibr/extractor/filesystem/os/homebrew"
"github.com/google/osv-scalibr/extractor/filesystem/os/kernel/module"
Expand Down Expand Up @@ -278,7 +278,7 @@ func setProtoMetadata(meta any, p *spb.Package) {
License: m.License,
},
}
case *dpkg.Metadata:
case *dpkgmeta.Metadata:
p.Metadata = &spb.Package_DpkgMetadata{
DpkgMetadata: &spb.DPKGPackageMetadata{
PackageName: m.PackageName,
Expand Down
15 changes: 9 additions & 6 deletions binary/proto/proto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/google/osv-scalibr/extractor/filesystem/language/python/requirements"
"github.com/google/osv-scalibr/extractor/filesystem/language/python/wheelegg"
"github.com/google/osv-scalibr/extractor/filesystem/os/dpkg"
dpkgmeta "github.com/google/osv-scalibr/extractor/filesystem/os/dpkg/metadata"
"github.com/google/osv-scalibr/extractor/filesystem/os/homebrew"
"github.com/google/osv-scalibr/extractor/filesystem/os/nix"
"github.com/google/osv-scalibr/extractor/filesystem/os/pacman"
Expand Down Expand Up @@ -168,9 +169,10 @@ func TestScanResultToProto(t *testing.T) {
failure := &plugin.ScanStatus{Status: plugin.ScanStatusFailed, FailureReason: "failure"}
failureProto := &spb.ScanStatus{Status: spb.ScanStatus_FAILED, FailureReason: "failure"}
purlDPKGPackage := &extractor.Package{
Name: "software",
Version: "1.0.0",
Metadata: &dpkg.Metadata{
Name: "software",
Version: "1.0.0",
PURLType: purl.TypeDebian,
Metadata: &dpkgmeta.Metadata{
PackageName: "software",
PackageVersion: "1.0.0",
OSID: "debian",
Expand All @@ -182,9 +184,10 @@ func TestScanResultToProto(t *testing.T) {
Extractor: dpkg.New(dpkg.DefaultConfig()),
}
purlDPKGAnnotationPackage := &extractor.Package{
Name: "software",
Version: "1.0.0",
Metadata: &dpkg.Metadata{
Name: "software",
Version: "1.0.0",
PURLType: purl.TypeDebian,
Metadata: &dpkgmeta.Metadata{
PackageName: "software",
PackageVersion: "1.0.0",
OSID: "debian",
Expand Down
3 changes: 3 additions & 0 deletions extractor/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
mavenpurl "github.com/google/osv-scalibr/extractor/filesystem/language/java/purl"
npmpurl "github.com/google/osv-scalibr/extractor/filesystem/language/javascript/purl"
"github.com/google/osv-scalibr/extractor/filesystem/language/python/pypipurl"
ospurl "github.com/google/osv-scalibr/extractor/filesystem/os/purl"
cdxmeta "github.com/google/osv-scalibr/extractor/filesystem/sbom/cdx/metadata"
cdxpurl "github.com/google/osv-scalibr/extractor/filesystem/sbom/cdx/purl"
spdxmeta "github.com/google/osv-scalibr/extractor/filesystem/sbom/spdx/metadata"
Expand Down Expand Up @@ -66,6 +67,8 @@ func typeSpecificPURL(p *Package) *purl.PackageURL {
return gopurl.MakePackageURL(p.Name, p.Version)
case purl.TypeHex:
return hexpurl.MakePackageURL(p.Name, p.Version)
case purl.TypeDebian, purl.TypeOpkg:
return ospurl.MakePackageURL(p.Name, p.Version, p.PURLType, p.Metadata)
case "windows":
return winpurl.MakePackageURL(p.Name, p.Version, p.Metadata)
}
Expand Down
45 changes: 45 additions & 0 deletions extractor/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/google/go-cmp/cmp"
"github.com/google/osv-scalibr/extractor"
dpkgmeta "github.com/google/osv-scalibr/extractor/filesystem/os/dpkg/metadata"
cdxmeta "github.com/google/osv-scalibr/extractor/filesystem/sbom/cdx/metadata"
spdxmeta "github.com/google/osv-scalibr/extractor/filesystem/sbom/spdx/metadata"
"github.com/google/osv-scalibr/purl"
Expand Down Expand Up @@ -139,6 +140,50 @@ func TestToPURL(t *testing.T) {
Version: "1.2.3",
},
},
{
name: "dpkg_purl",
pkg: &extractor.Package{
Name: "Name",
Version: "1.2.3",
PURLType: purl.TypeDebian,
Metadata: &dpkgmeta.Metadata{
PackageName: "pkg-name",
OSVersionCodename: "jammy",
},
Locations: []string{"location"},
},
want: &purl.PackageURL{
Type: purl.TypeDebian,
Namespace: "linux",
Name: "pkg-name",
Version: "1.2.3",
Qualifiers: purl.QualifiersFromMap(map[string]string{
purl.Distro: "jammy",
}),
},
},
{
name: "opkg_purl",
pkg: &extractor.Package{
Name: "Name",
Version: "1.2.3",
PURLType: purl.TypeOpkg,
Metadata: &dpkgmeta.Metadata{
PackageName: "pkg-name",
OSVersionCodename: "jammy",
},
Locations: []string{"location"},
},
want: &purl.PackageURL{
Type: purl.TypeOpkg,
Namespace: "linux",
Name: "pkg-name",
Version: "1.2.3",
Qualifiers: purl.QualifiersFromMap(map[string]string{
purl.Distro: "jammy",
}),
},
},
}

for _, tt := range tests {
Expand Down
84 changes: 16 additions & 68 deletions extractor/filesystem/os/dpkg/dpkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/google/osv-scalibr/extractor"
"github.com/google/osv-scalibr/extractor/filesystem"
"github.com/google/osv-scalibr/extractor/filesystem/internal/units"
dpkgmeta "github.com/google/osv-scalibr/extractor/filesystem/os/dpkg/metadata"
"github.com/google/osv-scalibr/extractor/filesystem/os/osrelease"
"github.com/google/osv-scalibr/inventory"
"github.com/google/osv-scalibr/log"
Expand Down Expand Up @@ -239,10 +240,16 @@ func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanI
annotations = append(annotations, extractor.Transitional)
}

purlType := purl.TypeDebian
if input.Path == "usr/lib/opkg/status" {
purlType = purl.TypeOpkg
}

p := &extractor.Package{
Name: pkgName,
Version: pkgVersion,
Metadata: &Metadata{
Name: pkgName,
Version: pkgVersion,
PURLType: purlType,
Metadata: &dpkgmeta.Metadata{
PackageName: pkgName,
PackageVersion: pkgVersion,
Status: h.Get("Status"),
Expand All @@ -260,8 +267,8 @@ func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanI
return pkgs, fmt.Errorf("parseSourceNameVersion(%q): %w", h.Get("Source"), err)
}
if sourceName != "" {
p.Metadata.(*Metadata).SourceName = sourceName
p.Metadata.(*Metadata).SourceVersion = sourceVersion
p.Metadata.(*dpkgmeta.Metadata).SourceName = sourceName
p.Metadata.(*dpkgmeta.Metadata).SourceVersion = sourceVersion
}

pkgs = append(pkgs, p)
Expand Down Expand Up @@ -296,75 +303,16 @@ func parseSourceNameVersion(source string) (string, string, error) {
return source, "", nil
}

func toNamespace(m *Metadata) string {
if m.OSID != "" {
return m.OSID
}
log.Errorf("os-release[ID] not set, fallback to 'linux'")
// TODO(b/298152210): Implement metric
return "linux"
}

func toDistro(m *Metadata) string {
// e.g. jammy
if m.OSVersionCodename != "" {
return m.OSVersionCodename
}
// fallback: e.g. 22.04
if m.OSVersionID != "" {
log.Warnf("VERSION_CODENAME not set in os-release, fallback to VERSION_ID")
return m.OSVersionID
}
log.Errorf("VERSION_CODENAME and VERSION_ID not set in os-release")
return ""
}

// ToPURL converts a package created by this extractor into a PURL.
// TODO(b/400910349): Remove and use Package.PURL() directly.
func (e Extractor) ToPURL(p *extractor.Package) *purl.PackageURL {
m := p.Metadata.(*Metadata)
q := map[string]string{}
distro := toDistro(m)
if distro != "" {
q[purl.Distro] = distro
}
if m.SourceName != "" {
q[purl.Source] = m.SourceName
}
if m.SourceVersion != "" {
q[purl.SourceVersion] = m.SourceVersion
}
if m.Architecture != "" {
q[purl.Arch] = m.Architecture
}

// Determine the package type (opkg or dpkg) based on file location
typePurl := ""

for _, location := range p.Locations {
if location == "usr/lib/opkg/status" {
typePurl = purl.TypeOpkg
break
}
}

// Default to dpkg if no specific file path matches
if typePurl == "" {
typePurl = purl.TypeDebian
}

return &purl.PackageURL{
Type: typePurl,
Name: m.PackageName,
Namespace: toNamespace(m),
Version: p.Version,
Qualifiers: purl.QualifiersFromMap(q),
}
return p.PURL()
}

// Ecosystem returns the OSV Ecosystem of the software extracted by this extractor.
func (Extractor) Ecosystem(p *extractor.Package) string {
m := p.Metadata.(*Metadata)
osID := cases.Title(language.English).String(toNamespace(m))
m := p.Metadata.(*dpkgmeta.Metadata)
osID := cases.Title(language.English).String(m.ToNamespace())
if m.OSVersionID == "" {
return osID
}
Expand Down
Loading
Loading