mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 07:40:48 -08:00
feat: reject unsupported artifact types in remote image retrieval (#9052)
Signed-off-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/remote"
|
||||
@@ -20,6 +21,11 @@ func tryRemote(ctx context.Context, imageName string, ref name.Reference, option
|
||||
if err != nil {
|
||||
return nil, cleanup, err
|
||||
}
|
||||
// ArtifactType being non-empty indicates this is not a regular container image
|
||||
// (e.g., Helm charts, WASM modules, or other OCI artifacts)
|
||||
if desc.ArtifactType != "" {
|
||||
return nil, cleanup, xerrors.Errorf("unsupported artifact type %q for image %q", desc.ArtifactType, imageName)
|
||||
}
|
||||
img, err := desc.Image()
|
||||
if err != nil {
|
||||
return nil, cleanup, err
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/registry"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
"github.com/google/go-containerregistry/pkg/v1/random"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
)
|
||||
|
||||
func Test_implicitReference_TagName(t *testing.T) {
|
||||
@@ -82,3 +92,100 @@ func Test_implicitReference_RepositoryName(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_tryRemote(t *testing.T) {
|
||||
// Create a test image
|
||||
img, err := random.Image(1024, 5)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the image digest for test expectations
|
||||
digest, err := img.Digest()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up registry server with null logger to suppress log output
|
||||
nullLogger := log.New(io.Discard, "", 0)
|
||||
s := httptest.NewServer(registry.New(registry.Logger(nullLogger)))
|
||||
t.Cleanup(s.Close)
|
||||
|
||||
u, err := url.Parse(s.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
imageName string
|
||||
setupImage func(t *testing.T, ref name.Reference)
|
||||
wantName string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "successful image retrieval",
|
||||
imageName: "test/alpine:3.10",
|
||||
setupImage: func(t *testing.T, ref name.Reference) {
|
||||
err := remote.Write(ref, img)
|
||||
require.NoError(t, err)
|
||||
},
|
||||
wantName: "/test/alpine:3.10",
|
||||
},
|
||||
{
|
||||
name: "helm chart config media type",
|
||||
imageName: "test/helm:chart",
|
||||
setupImage: func(t *testing.T, ref name.Reference) {
|
||||
configFile, err := img.ConfigFile()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a new config with helm chart media type
|
||||
imageToWrite, err := mutate.Config(img, configFile.Config)
|
||||
require.NoError(t, err)
|
||||
|
||||
imageToWrite = mutate.ConfigMediaType(imageToWrite, "application/vnd.cncf.helm.chart")
|
||||
|
||||
err = remote.Write(ref, imageToWrite)
|
||||
require.NoError(t, err)
|
||||
},
|
||||
wantErr: "unsupported artifact type",
|
||||
},
|
||||
{
|
||||
name: "image not found",
|
||||
imageName: "test/notfound:latest",
|
||||
wantErr: "NAME_UNKNOWN",
|
||||
setupImage: func(*testing.T, name.Reference) {},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Parse the image name with the test server address
|
||||
fullImageName := u.Host + "/" + tt.imageName
|
||||
ref, err := name.ParseReference(fullImageName)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up the image in registry if needed
|
||||
tt.setupImage(t, ref)
|
||||
|
||||
ctx := t.Context()
|
||||
got, cleanup, err := tryRemote(ctx, fullImageName, ref, types.ImageOptions{
|
||||
RegistryOptions: types.RegistryOptions{
|
||||
Insecure: true,
|
||||
},
|
||||
})
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
assert.ErrorContains(t, err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, got)
|
||||
assert.Contains(t, got.Name(), tt.wantName)
|
||||
|
||||
// Verify RepoTags and RepoDigests contain expected values
|
||||
repoTags := got.RepoTags()
|
||||
repoDigests := got.RepoDigests()
|
||||
assert.Len(t, repoTags, 1)
|
||||
assert.Contains(t, repoTags[0], tt.imageName)
|
||||
assert.Len(t, repoDigests, 1)
|
||||
assert.Contains(t, repoDigests[0], digest.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user