mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 17:03:17 +01:00
this PR makes the following changes to update the underlying license model to have more expressive capabilities it also provides some guarantee's surrounding the license values themselves - Licenses are updated from string -> pkg.LicenseSet which contain pkg.License with the following fields: - original `Value` read by syft - If it's possible to construct licenses will always have a valid SPDX expression for downstream consumption - the above is run against a generated list of SPDX license ID to try and find the correct ID - SPDX concluded vs declared is added to the new struct - URL source for license is added to the new struct - Location source is added to the new struct to show where the expression was pulled from
193 lines
5.7 KiB
Go
193 lines
5.7 KiB
Go
package source
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/go-multierror"
|
|
|
|
"github.com/anchore/stereoscope/pkg/file"
|
|
"github.com/anchore/stereoscope/pkg/image"
|
|
)
|
|
|
|
// Location represents a path relative to a particular filesystem resolved to a specific file.Reference. This struct is used as a key
|
|
// in content fetching to uniquely identify a file relative to a request (the VirtualPath).
|
|
type Location struct {
|
|
LocationData `cyclonedx:""`
|
|
LocationMetadata `cyclonedx:""`
|
|
}
|
|
|
|
type LocationData struct {
|
|
Coordinates `cyclonedx:""` // Empty string here means there is no intermediate property name, e.g. syft:locations:0:path without "coordinates"
|
|
// note: it is IMPORTANT to ignore anything but the coordinates for a Location when considering the ID (hash value)
|
|
// since the coordinates are the minimally correct ID for a location (symlinks should not come into play)
|
|
VirtualPath string `hash:"ignore" json:"-"` // The path to the file which may or may not have hardlinks / symlinks
|
|
ref file.Reference `hash:"ignore"` // The file reference relative to the stereoscope.FileCatalog that has more information about this location.
|
|
}
|
|
|
|
type LocationMetadata struct {
|
|
Annotations map[string]string `json:"annotations,omitempty"` // Arbitrary key-value pairs that can be used to annotate a location
|
|
}
|
|
|
|
func (m *LocationMetadata) merge(other LocationMetadata) error {
|
|
var errs error
|
|
for k, v := range other.Annotations {
|
|
if otherV, ok := m.Annotations[k]; ok {
|
|
if v != otherV {
|
|
err := fmt.Errorf("unable to merge location metadata: conflicting values for key=%q: %q != %q", k, v, otherV)
|
|
errs = multierror.Append(errs, err)
|
|
continue
|
|
}
|
|
}
|
|
m.Annotations[k] = v
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func (l Location) WithAnnotation(key, value string) Location {
|
|
if l.LocationMetadata.Annotations == nil {
|
|
l.LocationMetadata.Annotations = map[string]string{}
|
|
}
|
|
l.LocationMetadata.Annotations[key] = value
|
|
return l
|
|
}
|
|
|
|
func (l Location) WithoutAnnotations() Location {
|
|
l.LocationMetadata.Annotations = map[string]string{}
|
|
|
|
return l
|
|
}
|
|
|
|
// NewLocation creates a new Location representing a path without denoting a filesystem or FileCatalog reference.
|
|
func NewLocation(realPath string) Location {
|
|
return Location{
|
|
LocationData: LocationData{
|
|
Coordinates: Coordinates{
|
|
RealPath: realPath,
|
|
},
|
|
},
|
|
LocationMetadata: LocationMetadata{
|
|
Annotations: map[string]string{},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewVirtualLocation creates a new location for a path accessed by a virtual path (a path with a symlink or hardlink somewhere in the path)
|
|
func NewVirtualLocation(realPath, virtualPath string) Location {
|
|
return Location{
|
|
LocationData: LocationData{
|
|
Coordinates: Coordinates{
|
|
RealPath: realPath,
|
|
},
|
|
VirtualPath: virtualPath,
|
|
},
|
|
LocationMetadata: LocationMetadata{
|
|
Annotations: map[string]string{},
|
|
}}
|
|
}
|
|
|
|
// NewLocationFromCoordinates creates a new location for the given Coordinates.
|
|
func NewLocationFromCoordinates(coordinates Coordinates) Location {
|
|
return Location{
|
|
LocationData: LocationData{
|
|
Coordinates: coordinates,
|
|
},
|
|
LocationMetadata: LocationMetadata{
|
|
Annotations: map[string]string{},
|
|
}}
|
|
}
|
|
|
|
// NewVirtualLocationFromCoordinates creates a new location for the given Coordinates via a virtual path.
|
|
func NewVirtualLocationFromCoordinates(coordinates Coordinates, virtualPath string) Location {
|
|
return Location{
|
|
LocationData: LocationData{
|
|
Coordinates: coordinates,
|
|
VirtualPath: virtualPath,
|
|
},
|
|
LocationMetadata: LocationMetadata{
|
|
Annotations: map[string]string{},
|
|
}}
|
|
}
|
|
|
|
// NewLocationFromImage creates a new Location representing the given path (extracted from the ref) relative to the given image.
|
|
func NewLocationFromImage(virtualPath string, ref file.Reference, img *image.Image) Location {
|
|
layer := img.FileCatalog.Layer(ref)
|
|
return Location{
|
|
LocationData: LocationData{
|
|
Coordinates: Coordinates{
|
|
RealPath: string(ref.RealPath),
|
|
FileSystemID: layer.Metadata.Digest,
|
|
},
|
|
VirtualPath: virtualPath,
|
|
ref: ref,
|
|
},
|
|
LocationMetadata: LocationMetadata{
|
|
Annotations: map[string]string{},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewLocationFromDirectory creates a new Location representing the given path (extracted from the ref) relative to the given directory.
|
|
func NewLocationFromDirectory(responsePath string, ref file.Reference) Location {
|
|
return Location{
|
|
LocationData: LocationData{
|
|
Coordinates: Coordinates{
|
|
RealPath: responsePath,
|
|
},
|
|
ref: ref,
|
|
},
|
|
LocationMetadata: LocationMetadata{
|
|
Annotations: map[string]string{},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewVirtualLocationFromDirectory creates a new Location representing the given path (extracted from the ref) relative to the given directory with a separate virtual access path.
|
|
func NewVirtualLocationFromDirectory(responsePath, virtualResponsePath string, ref file.Reference) Location {
|
|
if responsePath == virtualResponsePath {
|
|
return NewLocationFromDirectory(responsePath, ref)
|
|
}
|
|
return Location{
|
|
LocationData: LocationData{
|
|
Coordinates: Coordinates{
|
|
RealPath: responsePath,
|
|
},
|
|
VirtualPath: virtualResponsePath,
|
|
ref: ref,
|
|
},
|
|
LocationMetadata: LocationMetadata{
|
|
Annotations: map[string]string{},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (l Location) AccessPath() string {
|
|
if l.VirtualPath != "" {
|
|
return l.VirtualPath
|
|
}
|
|
return l.RealPath
|
|
}
|
|
|
|
func (l Location) String() string {
|
|
str := ""
|
|
if l.ref.ID() != 0 {
|
|
str += fmt.Sprintf("id=%d ", l.ref.ID())
|
|
}
|
|
|
|
str += fmt.Sprintf("RealPath=%q", l.RealPath)
|
|
|
|
if l.VirtualPath != "" {
|
|
str += fmt.Sprintf(" VirtualPath=%q", l.VirtualPath)
|
|
}
|
|
|
|
if l.FileSystemID != "" {
|
|
str += fmt.Sprintf(" Layer=%q", l.FileSystemID)
|
|
}
|
|
return fmt.Sprintf("Location<%s>", str)
|
|
}
|
|
|
|
func (l Location) Equals(other Location) bool {
|
|
return l.RealPath == other.RealPath &&
|
|
l.VirtualPath == other.VirtualPath &&
|
|
l.FileSystemID == other.FileSystemID
|
|
}
|