github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/os/ecosystem/ecosystem.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package ecosystem converts OS package details into PackageURLs.
    16  package ecosystem
    17  
    18  import (
    19  	"strings"
    20  
    21  	apkmeta "github.com/google/osv-scalibr/extractor/filesystem/os/apk/metadata"
    22  	dpkgmeta "github.com/google/osv-scalibr/extractor/filesystem/os/dpkg/metadata"
    23  	modulemeta "github.com/google/osv-scalibr/extractor/filesystem/os/kernel/module/metadata"
    24  	vmlinuzmeta "github.com/google/osv-scalibr/extractor/filesystem/os/kernel/vmlinuz/metadata"
    25  	pacmanmeta "github.com/google/osv-scalibr/extractor/filesystem/os/pacman/metadata"
    26  	portagemeta "github.com/google/osv-scalibr/extractor/filesystem/os/portage/metadata"
    27  	rpmmeta "github.com/google/osv-scalibr/extractor/filesystem/os/rpm/metadata"
    28  	snapmeta "github.com/google/osv-scalibr/extractor/filesystem/os/snap/metadata"
    29  	"github.com/google/osv-scalibr/inventory/osvecosystem"
    30  	"github.com/google/osv-scalibr/log"
    31  	"github.com/ossf/osv-schema/bindings/go/osvconstants"
    32  	"golang.org/x/text/cases"
    33  	"golang.org/x/text/language"
    34  )
    35  
    36  // MakeEcosystem computes the OSV Ecosystem value from an OS package's metadata.
    37  func MakeEcosystem(metadata any) osvecosystem.Parsed {
    38  	namespace := ""
    39  	osVersionID := ""
    40  	switch m := metadata.(type) {
    41  	case *apkmeta.Metadata:
    42  		version := m.ToDistro()
    43  		if version == "" {
    44  			return osvecosystem.FromEcosystem(osvconstants.EcosystemAlpine)
    45  		}
    46  		if m.OSID == "alpaquita" {
    47  			return osvecosystem.Parsed{Ecosystem: osvconstants.EcosystemAlpaquita, Suffix: m.OSVersionID}
    48  		}
    49  		if m.OSID == "bellsoft-hardened-containers" {
    50  			return osvecosystem.Parsed{Ecosystem: osvconstants.EcosystemBellSoftHardenedContainers, Suffix: m.OSVersionID}
    51  		}
    52  		return osvecosystem.Parsed{Ecosystem: osvconstants.EcosystemAlpine, Suffix: m.TrimDistroVersion(version)}
    53  
    54  	case *dpkgmeta.Metadata:
    55  		namespace = m.ToNamespace()
    56  		osVersionID = m.OSVersionID
    57  
    58  	case *rpmmeta.Metadata:
    59  		if m.OSID == "rhel" {
    60  			// CPE_NAME="cpe:/o:redhat:enterprise_linux:9::baseos"
    61  			// If :redhat: doesn't exist, then suffix will just be empty and have no suffix.
    62  			_, suffix, _ := strings.Cut(m.OSCPEName, ":redhat:")
    63  			return osvecosystem.Parsed{Ecosystem: osvconstants.EcosystemRedHat, Suffix: suffix}
    64  		}
    65  		if m.OSID == "rocky" {
    66  			return osvecosystem.FromEcosystem(osvconstants.EcosystemRockyLinux)
    67  		}
    68  		if m.OSID == "openEuler" {
    69  			return osvecosystem.Parsed{Ecosystem: osvconstants.EcosystemOpenEuler, Suffix: m.OpenEulerEcosystemSuffix()}
    70  		}
    71  
    72  	case *snapmeta.Metadata:
    73  		if m.OSID == "ubuntu" {
    74  			return osvecosystem.FromEcosystem(osvconstants.EcosystemUbuntu)
    75  		}
    76  		log.Errorf("os-release[ID] not set, fallback to '' ecosystem")
    77  		return osvecosystem.Parsed{}
    78  
    79  	case *pacmanmeta.Metadata:
    80  		namespace = m.ToNamespace()
    81  		osVersionID = m.OSVersionID
    82  
    83  	case *portagemeta.Metadata:
    84  		namespace = m.ToNamespace()
    85  		osVersionID = m.OSVersionID
    86  
    87  	case *vmlinuzmeta.Metadata:
    88  		namespace = m.ToNamespace()
    89  		osVersionID = m.OSVersionID
    90  
    91  	case *modulemeta.Metadata:
    92  		namespace = m.ToNamespace()
    93  		osVersionID = m.OSVersionID
    94  
    95  	default:
    96  		return osvecosystem.Parsed{}
    97  	}
    98  
    99  	osID := cases.Title(language.English).String(namespace)
   100  	parsed, err := osvecosystem.Parse(osID)
   101  	if err != nil {
   102  		return osvecosystem.Parsed{}
   103  	}
   104  
   105  	if osVersionID == "" {
   106  		return parsed
   107  	}
   108  
   109  	parsed.Suffix = osVersionID
   110  	if parsed.GetValidity() != nil {
   111  		return osvecosystem.Parsed{}
   112  	}
   113  
   114  	return parsed
   115  }