mirror of
https://github.com/anchore/syft.git
synced 2026-10-31 22:46:36 +01:00
Add platform selection (#866)
This commit is contained in:
@@ -15,6 +15,9 @@ type ImageMetadata struct {
|
||||
RawManifest []byte `json:"manifest"`
|
||||
RawConfig []byte `json:"config"`
|
||||
RepoDigests []string `json:"repoDigests"`
|
||||
Architecture string `json:"architecture"`
|
||||
Variant string `json:"architectureVariant,omitempty"`
|
||||
OS string `json:"os"`
|
||||
}
|
||||
|
||||
// LayerMetadata represents all static metadata that defines what a container image layer is.
|
||||
@@ -42,6 +45,9 @@ func NewImageMetadata(img *image.Image, userInput string) ImageMetadata {
|
||||
RawConfig: img.Metadata.RawConfig,
|
||||
RawManifest: img.Metadata.RawManifest,
|
||||
RepoDigests: img.Metadata.RepoDigests,
|
||||
Architecture: img.Metadata.Architecture,
|
||||
Variant: img.Metadata.Variant,
|
||||
OS: img.Metadata.OS,
|
||||
}
|
||||
|
||||
// populate image metadata
|
||||
|
||||
+22
-6
@@ -40,12 +40,13 @@ type Input struct {
|
||||
Scheme Scheme
|
||||
ImageSource image.Source
|
||||
Location string
|
||||
Platform string
|
||||
autoDetectAvailableImageSources bool
|
||||
}
|
||||
|
||||
// ParseInput generates a source Input that can be used as an argument to generate a new source
|
||||
// from specific providers including a registry.
|
||||
func ParseInput(userInput string, detectAvailableImageSources bool) (*Input, error) {
|
||||
func ParseInput(userInput string, platform string, detectAvailableImageSources bool) (*Input, error) {
|
||||
fs := afero.NewOsFs()
|
||||
scheme, source, location, err := DetectScheme(fs, image.DetectSource, userInput)
|
||||
if err != nil {
|
||||
@@ -71,12 +72,17 @@ func ParseInput(userInput string, detectAvailableImageSources bool) (*Input, err
|
||||
}
|
||||
}
|
||||
|
||||
if scheme != ImageScheme && platform != "" {
|
||||
return nil, fmt.Errorf("cannot specify a platform for a non-image source")
|
||||
}
|
||||
|
||||
// collect user input for downstream consumption
|
||||
return &Input{
|
||||
UserInput: userInput,
|
||||
Scheme: scheme,
|
||||
ImageSource: source,
|
||||
Location: location,
|
||||
Platform: platform,
|
||||
autoDetectAvailableImageSources: detectAvailableImageSources,
|
||||
}, nil
|
||||
}
|
||||
@@ -147,10 +153,19 @@ func getImageWithRetryStrategy(in Input, registryOptions *image.RegistryOptions)
|
||||
opts = append(opts, stereoscope.WithRegistryOptions(*registryOptions))
|
||||
}
|
||||
|
||||
if in.Platform != "" {
|
||||
opts = append(opts, stereoscope.WithPlatform(in.Platform))
|
||||
}
|
||||
|
||||
img, err := stereoscope.GetImageFromSource(ctx, in.Location, in.ImageSource, opts...)
|
||||
cleanup := func() {
|
||||
if err := img.Cleanup(); err != nil {
|
||||
log.Warnf("unable to cleanup image=%q: %w", in.UserInput, err)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
// Success on the first try!
|
||||
return img, stereoscope.Cleanup, nil
|
||||
return img, cleanup, nil
|
||||
}
|
||||
|
||||
scheme := parseScheme(in.UserInput)
|
||||
@@ -180,11 +195,12 @@ func getImageWithRetryStrategy(in Input, registryOptions *image.RegistryOptions)
|
||||
in.ImageSource = image.DetermineDefaultImagePullSource(in.UserInput)
|
||||
}
|
||||
img, err = stereoscope.GetImageFromSource(ctx, in.UserInput, in.ImageSource, opts...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
cleanup = func() {
|
||||
if err := img.Cleanup(); err != nil {
|
||||
log.Warnf("unable to cleanup image=%q: %w", in.UserInput, err)
|
||||
}
|
||||
}
|
||||
|
||||
return img, stereoscope.Cleanup, nil
|
||||
return img, cleanup, err
|
||||
}
|
||||
|
||||
func generateDirectorySource(fs afero.Fs, location string) (*Source, func(), error) {
|
||||
|
||||
@@ -26,22 +26,34 @@ func TestParseInput(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
platform string
|
||||
expected Scheme
|
||||
errFn require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "ParseInput parses a file input",
|
||||
input: "test-fixtures/image-simple/file-1.txt",
|
||||
expected: FileScheme,
|
||||
},
|
||||
{
|
||||
name: "errors out when using platform for non-image scheme",
|
||||
input: "test-fixtures/image-simple/file-1.txt",
|
||||
platform: "arm64",
|
||||
errFn: require.Error,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
sourceInput, err := ParseInput(test.input, true)
|
||||
if err != nil {
|
||||
t.Errorf("failed to ParseInput")
|
||||
if test.errFn == nil {
|
||||
test.errFn = require.NoError
|
||||
}
|
||||
sourceInput, err := ParseInput(test.input, test.platform, true)
|
||||
test.errFn(t, err)
|
||||
if test.expected != "" {
|
||||
require.NotNil(t, sourceInput)
|
||||
assert.Equal(t, sourceInput.Scheme, test.expected)
|
||||
}
|
||||
assert.Equal(t, sourceInput.Scheme, test.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -452,7 +464,7 @@ func TestDirectoryExclusions(t *testing.T) {
|
||||
registryOpts := &image.RegistryOptions{}
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
sourceInput, err := ParseInput("dir:"+test.input, false)
|
||||
sourceInput, err := ParseInput("dir:"+test.input, "", false)
|
||||
require.NoError(t, err)
|
||||
src, fn, err := New(*sourceInput, registryOpts, test.exclusions)
|
||||
defer fn()
|
||||
@@ -546,7 +558,7 @@ func TestImageExclusions(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
archiveLocation := imagetest.PrepareFixtureImage(t, "docker-archive", test.input)
|
||||
sourceInput, err := ParseInput(archiveLocation, false)
|
||||
sourceInput, err := ParseInput(archiveLocation, "", false)
|
||||
require.NoError(t, err)
|
||||
src, fn, err := New(*sourceInput, registryOpts, test.exclusions)
|
||||
defer fn()
|
||||
|
||||
Reference in New Issue
Block a user