mirror of
https://github.com/anchore/syft.git
synced 2026-10-31 06:26:30 +01:00
Introduce minimal source coordinates (#623)
* split source.Location and create source.Coordinates for minimal path addressing Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * move coordinates into separate file Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * Update syft/source/coordinates.go Co-authored-by: Dan Luhring <luhring@users.noreply.github.com>
This commit is contained in:
co-authored by
Dan Luhring
parent
9090c3a772
commit
e38cde35ed
@@ -0,0 +1,34 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
)
|
||||
|
||||
// Coordinates contains the minimal information needed to describe how to find a file within any possible source object (e.g. image and directory sources)
|
||||
type Coordinates struct {
|
||||
RealPath string `json:"path"` // The path where all path ancestors have no hardlinks / symlinks
|
||||
FileSystemID string `json:"layerID,omitempty"` // An ID representing the filesystem. For container images, this is a layer digest. For directories or a root filesystem, this is blank.
|
||||
}
|
||||
|
||||
func (c Coordinates) ID() artifact.ID {
|
||||
f, err := artifact.IDFromHash(c)
|
||||
if err != nil {
|
||||
// TODO: what to do in this case?
|
||||
log.Warnf("unable to get fingerprint of location coordinate=%+v: %+v", c, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (c Coordinates) String() string {
|
||||
str := fmt.Sprintf("RealPath=%q", c.RealPath)
|
||||
|
||||
if c.FileSystemID != "" {
|
||||
str += fmt.Sprintf(" Layer=%q", c.FileSystemID)
|
||||
}
|
||||
return fmt.Sprintf("Location<%s>", str)
|
||||
}
|
||||
+46
-27
@@ -3,28 +3,46 @@ package source
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/hashstructure/v2"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/image"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
)
|
||||
|
||||
var _ hashstructure.Hashable = (*Location)(nil)
|
||||
|
||||
// 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). Note that the VirtualPath
|
||||
// and ref are ignored fields when using github.com/mitchellh/hashstructure. The reason for this is to ensure that
|
||||
// only the minimally expressible fields of a location are baked into the uniqueness of a Location. Since VirutalPath
|
||||
// and ref are not captured in JSON output they cannot be included in this minimal definition.
|
||||
// in content fetching to uniquely identify a file relative to a request (the VirtualPath).
|
||||
type Location struct {
|
||||
RealPath string `json:"path"` // The path where all path ancestors have no hardlinks / symlinks
|
||||
VirtualPath string `hash:"ignore" json:"-"` // The path to the file which may or may not have hardlinks / symlinks
|
||||
FileSystemID string `json:"layerID,omitempty"` // An ID representing the filesystem. For container images this is a layer digest, directories or root filesystem this is blank.
|
||||
ref file.Reference `hash:"ignore"` // The file reference relative to the stereoscope.FileCatalog that has more information about this location.
|
||||
Coordinates
|
||||
VirtualPath string // The path to the file which may or may not have hardlinks / symlinks
|
||||
ref file.Reference // The file reference relative to the stereoscope.FileCatalog that has more information about this location.
|
||||
}
|
||||
|
||||
// NewLocation creates a new Location representing a path without denoting a filesystem or FileCatalog reference.
|
||||
func NewLocation(path string) Location {
|
||||
func NewLocation(realPath string) Location {
|
||||
return Location{
|
||||
RealPath: path,
|
||||
Coordinates: Coordinates{
|
||||
RealPath: realPath,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 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{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: realPath,
|
||||
},
|
||||
VirtualPath: virtualPath,
|
||||
}
|
||||
}
|
||||
|
||||
// NewLocationFromCoordinates creates a new location for the given Coordinates.
|
||||
func NewLocationFromCoordinates(coordinates Coordinates) Location {
|
||||
return Location{
|
||||
Coordinates: coordinates,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,25 +52,31 @@ func NewLocationFromImage(virtualPath string, ref file.Reference, img *image.Ima
|
||||
if err != nil {
|
||||
log.Warnf("unable to find file catalog entry for ref=%+v", ref)
|
||||
return Location{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: string(ref.RealPath),
|
||||
},
|
||||
VirtualPath: virtualPath,
|
||||
RealPath: string(ref.RealPath),
|
||||
ref: ref,
|
||||
}
|
||||
}
|
||||
|
||||
return Location{
|
||||
VirtualPath: virtualPath,
|
||||
RealPath: string(ref.RealPath),
|
||||
FileSystemID: entry.Layer.Metadata.Digest,
|
||||
ref: ref,
|
||||
Coordinates: Coordinates{
|
||||
RealPath: string(ref.RealPath),
|
||||
FileSystemID: entry.Layer.Metadata.Digest,
|
||||
},
|
||||
VirtualPath: virtualPath,
|
||||
ref: ref,
|
||||
}
|
||||
}
|
||||
|
||||
// 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{
|
||||
RealPath: responsePath,
|
||||
ref: ref,
|
||||
Coordinates: Coordinates{
|
||||
RealPath: responsePath,
|
||||
},
|
||||
ref: ref,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,13 +98,8 @@ func (l Location) String() string {
|
||||
return fmt.Sprintf("Location<%s>", str)
|
||||
}
|
||||
|
||||
func (l Location) ID() artifact.ID {
|
||||
f, err := artifact.IDFromHash(l)
|
||||
if err != nil {
|
||||
// TODO: what to do in this case?
|
||||
log.Warnf("unable to get fingerprint of location=%+v: %+v", l, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return f
|
||||
func (l Location) Hash() (uint64, error) {
|
||||
// since location is part of the package definition it is important that only coordinates are used during object
|
||||
// hashing. (Location hash should be a pass-through for the coordinates and not include ref or VirtualPath.)
|
||||
return hashstructure.Hash(l.ID(), hashstructure.FormatV2, nil)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user