github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/os/purl/purl.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 purl converts OS package details into PackageURLs.
    16  package purl
    17  
    18  import (
    19  	"strconv"
    20  	"strings"
    21  
    22  	apkmeta "github.com/google/osv-scalibr/extractor/filesystem/os/apk/metadata"
    23  	cosmeta "github.com/google/osv-scalibr/extractor/filesystem/os/cos/metadata"
    24  	dpkgmeta "github.com/google/osv-scalibr/extractor/filesystem/os/dpkg/metadata"
    25  	flatpakmeta "github.com/google/osv-scalibr/extractor/filesystem/os/flatpak/metadata"
    26  	nixmeta "github.com/google/osv-scalibr/extractor/filesystem/os/nix/metadata"
    27  	pacmanmeta "github.com/google/osv-scalibr/extractor/filesystem/os/pacman/metadata"
    28  	portagemeta "github.com/google/osv-scalibr/extractor/filesystem/os/portage/metadata"
    29  	rpmmeta "github.com/google/osv-scalibr/extractor/filesystem/os/rpm/metadata"
    30  	snapmeta "github.com/google/osv-scalibr/extractor/filesystem/os/snap/metadata"
    31  	"github.com/google/osv-scalibr/purl"
    32  )
    33  
    34  // MakePackageURL returns a package URL that follows the specific OS's spec
    35  // and includes OS version info.
    36  func MakePackageURL(name string, version string, purlType string, metadata any) *purl.PackageURL {
    37  	q := map[string]string{}
    38  	var namespace string
    39  	switch m := metadata.(type) {
    40  	case *apkmeta.Metadata:
    41  		namespace = m.ToNamespace()
    42  		name = strings.ToLower(name)
    43  		if distro := m.ToDistro(); distro != "" {
    44  			q[purl.Distro] = distro
    45  		}
    46  		if m.OriginName != "" {
    47  			q[purl.Origin] = m.OriginName
    48  		}
    49  		if m.Architecture != "" {
    50  			q[purl.Arch] = m.Architecture
    51  		}
    52  
    53  	case *cosmeta.Metadata:
    54  		if distro := m.ToDistro(); distro != "" {
    55  			q[purl.Distro] = distro
    56  		}
    57  
    58  	case *dpkgmeta.Metadata:
    59  		namespace = m.ToNamespace()
    60  		name = m.PackageName
    61  
    62  		if distro := m.ToDistro(); distro != "" {
    63  			q[purl.Distro] = distro
    64  		}
    65  		if m.SourceName != "" {
    66  			q[purl.Source] = m.SourceName
    67  		}
    68  		if m.SourceVersion != "" {
    69  			q[purl.SourceVersion] = m.SourceVersion
    70  		}
    71  		if m.Architecture != "" {
    72  			q[purl.Arch] = m.Architecture
    73  		}
    74  
    75  	case *flatpakmeta.Metadata:
    76  		namespace = m.ToNamespace()
    77  		if distro := m.ToDistro(); distro != "" {
    78  			q[purl.Distro] = distro
    79  		}
    80  
    81  	case *rpmmeta.Metadata:
    82  		namespace = m.ToNamespace()
    83  		if m.Epoch > 0 {
    84  			q[purl.Epoch] = strconv.Itoa(m.Epoch)
    85  		}
    86  		if distro := m.ToDistro(); distro != "" {
    87  			q[purl.Distro] = distro
    88  		}
    89  		if m.SourceRPM != "" {
    90  			q[purl.SourceRPM] = m.SourceRPM
    91  		}
    92  		if m.Architecture != "" {
    93  			q[purl.Arch] = m.Architecture
    94  		}
    95  
    96  	case *snapmeta.Metadata:
    97  		namespace = m.ToNamespace()
    98  		if distro := m.ToDistro(); distro != "" {
    99  			q[purl.Distro] = distro
   100  		}
   101  
   102  	case *pacmanmeta.Metadata:
   103  		namespace = m.ToNamespace()
   104  		name = m.PackageName
   105  		if distro := m.ToDistro(); distro != "" {
   106  			q[purl.Distro] = distro
   107  		}
   108  		if m.PackageDependencies != "" {
   109  			q[purl.PackageDependencies] = m.PackageDependencies
   110  		}
   111  
   112  	case *portagemeta.Metadata:
   113  		namespace = m.ToNamespace()
   114  		name = m.PackageName
   115  		version = m.PackageVersion
   116  		if distro := m.ToDistro(); distro != "" {
   117  			q[purl.Distro] = distro
   118  		}
   119  
   120  	case *nixmeta.Metadata:
   121  		if distro := m.ToDistro(); distro != "" {
   122  			q[purl.Distro] = distro
   123  		}
   124  
   125  	default:
   126  		return nil
   127  	}
   128  
   129  	return &purl.PackageURL{
   130  		Type:       purlType,
   131  		Name:       name,
   132  		Namespace:  namespace,
   133  		Version:    version,
   134  		Qualifiers: purl.QualifiersFromMap(q),
   135  	}
   136  }