diff --git a/e2e/main_test.go b/e2e/main_test.go index 0f62ed1b..26250d72 100644 --- a/e2e/main_test.go +++ b/e2e/main_test.go @@ -139,20 +139,17 @@ func TestSignedComponentUploadToLocalOCIRegistry(t *testing.T) { Assess("Validate Component "+podinfoComponentName, checkRepositoryExistsInRegistry(componentNamePrefix+componentNameIdentifier+podinfoComponentName)). Assess("Validate Component "+podinfoBackendComponentName, checkRepositoryExistsInRegistry(componentNamePrefix+componentNameIdentifier+podinfoBackendComponentName)). Assess("Validate Component "+podinfoFrontendComponentName, checkRepositoryExistsInRegistry(componentNamePrefix+componentNameIdentifier+podinfoFrontendComponentName)). - Assess("Validate Component "+redisComponentName, checkRepositoryExistsInRegistry(componentNamePrefix+componentNameIdentifier+redisComponentName)) - - signatureVerificationFailed := features.New("Validate if invalid signed OCM Components are present in OCI Registry"). - Assess("Check that component version "+cvName+"is ready and signature verification failed", checkIsComponentVersionFailed(cvName)). + Assess("Validate Component "+redisComponentName, checkRepositoryExistsInRegistry(componentNamePrefix+componentNameIdentifier+redisComponentName)). Teardown(shared.DeleteSecret(keyName)) signatureVerification := features.New("Validate if signed Component Versions of OCM Components exist"). WithStep("create valid rsa key secret", 1, shared.CreateSecret(keyName, map[string][]byte{keyName: publicKey}, nil, "")). - Assess("Check that component version "+cvName+" is ready and signature was verified", checkIsComponentVersionReady(cvName, ocmNamespace)) + Assess("Check that component version "+cvName+" is ready and signature was verified", checkIsComponentVersionReady(cvName, ocmNamespace)). + Teardown(shared.DeleteSecret(keyName)) testEnv.Test(t, setupComponent.Feature(), validation.Feature(), - signatureVerificationFailed.Feature(), signatureVerification.Feature(), ) } diff --git a/pkg/ocm/fakes/fakes.go b/pkg/ocm/fakes/fakes.go index 22b05e9f..26fb4763 100644 --- a/pkg/ocm/fakes/fakes.go +++ b/pkg/ocm/fakes/fakes.go @@ -150,7 +150,7 @@ func (m *MockFetcher) GetLatestComponentVersionWasNotCalled() bool { return len(m.getLatestComponentVersionCalledWith) == 0 } -func (m *MockFetcher) ListComponentVersions(logger logr.Logger, octx ocm.Context, obj *v1alpha1.ComponentVersion) ([]ocmctrl.Version, error) { +func (m *MockFetcher) ListComponentVersions(_ context.Context, _ logr.Logger, _ ocm.Context, obj *v1alpha1.ComponentVersion) ([]ocmctrl.Version, error) { m.listComponentVersionsCalledWith = append(m.listComponentVersionsCalledWith, []any{obj}) return m.listComponentVersionsVersions, m.listComponentVersionsErr } diff --git a/pkg/ocm/ocm.go b/pkg/ocm/ocm.go index 9c760ffd..3cc5568b 100644 --- a/pkg/ocm/ocm.go +++ b/pkg/ocm/ocm.go @@ -58,7 +58,7 @@ type Contract interface { repositoryURL, name, version string, ) (ocm.ComponentVersionAccess, error) GetLatestValidComponentVersion(ctx context.Context, octx ocm.Context, obj *v1alpha1.ComponentVersion) (string, error) - ListComponentVersions(logger logr.Logger, octx ocm.Context, obj *v1alpha1.ComponentVersion) ([]Version, error) + ListComponentVersions(ctx context.Context, logger logr.Logger, octx ocm.Context, obj *v1alpha1.ComponentVersion) ([]Version, error) VerifyComponent(ctx context.Context, octx ocm.Context, obj *v1alpha1.ComponentVersion, version string) (bool, error) TransferComponent( octx ocm.Context, @@ -427,7 +427,7 @@ func (c *Client) GetLatestValidComponentVersion( ) (string, error) { logger := log.FromContext(ctx) - versions, err := c.ListComponentVersions(logger, octx, obj) + versions, err := c.ListComponentVersions(ctx, logger, octx, obj) if err != nil { return "", fmt.Errorf("failed to get component versions: %w", err) } @@ -447,6 +447,14 @@ func (c *Client) GetLatestValidComponentVersion( for _, v := range versions { if valid, _ := constraint.Validate(v.Semver); valid { + if len(obj.Spec.Verify) > 0 { + if _, err := c.VerifyComponent(ctx, octx, obj, v.Version); err != nil { + logger.Error(err, "ignoring version as it failed verification", "version", v.Version, "component", obj.Spec.Component) + + continue + } + } + return v.Version, nil } } @@ -462,6 +470,7 @@ type Version struct { } func (c *Client) ListComponentVersions( + _ context.Context, logger logr.Logger, octx ocm.Context, obj *v1alpha1.ComponentVersion, diff --git a/pkg/ocm/ocm_test.go b/pkg/ocm/ocm_test.go index 5ba072fa..bcade1c5 100644 --- a/pkg/ocm/ocm_test.go +++ b/pkg/ocm/ocm_test.go @@ -555,6 +555,11 @@ func TestClient_CreateAuthenticatedOCMContextWithServiceAccount(t *testing.T) { } func TestClient_GetLatestValidComponentVersion(t *testing.T) { + publicKey1, err := os.ReadFile(filepath.Join("testdata", "public1_key.pem")) + require.NoError(t, err) + privateKey, err := os.ReadFile(filepath.Join("testdata", "private_key.pem")) + require.NoError(t, err) + testCases := []struct { name string componentVersion func(name string) *v1alpha1.ComponentVersion @@ -709,12 +714,79 @@ func TestClient_GetLatestValidComponentVersion(t *testing.T) { expectedVersion: "v0.0.5", }, + { + name: "latest _verified_ version is returned", + componentVersion: func(name string) *v1alpha1.ComponentVersion { + return &v1alpha1.ComponentVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "default", + }, + Spec: v1alpha1.ComponentVersionSpec{ + Component: name, + Version: v1alpha1.Version{ + Semver: ">=v0.0.1", + }, + Repository: v1alpha1.Repository{ + URL: "localhost", + }, + Verify: []v1alpha1.Signature{ + { + Name: Signature, + PublicKey: v1alpha1.PublicKey{ + SecretRef: &corev1.LocalObjectReference{ + Name: "sign-secret", + }, + }, + }, + }, + }, + } + }, + setupComponents: func(name string, context *fakeocm.Context) { + for _, v := range []string{"v0.0.1", "v0.0.2", "v0.0.4", "v0.0.5"} { + if v == "v0.0.4" { + // sign it + _ = context.AddComponent(&fakeocm.Component{ + Name: name, + Version: v, + Sign: &fakeocm.Sign{ + Name: Signature, + PrivKey: privateKey, + PubKey: publicKey1, + Digest: "3d879ecdea45acb7f8d85b89fd653288d84af4476eac4141822142ec59c13745", + }, + }) + + continue + } + + _ = context.AddComponent(&fakeocm.Component{ + Name: name, + Version: v, + }) + } + }, + + expectedVersion: "v0.0.4", // v0.0.4 is the only signed version and should be returned. + }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { t.Helper() - fakeKubeClient := env.FakeKubeClient() + secretName := "sign-secret" + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretName, + Namespace: "default", + }, + Data: map[string][]byte{ + Signature: publicKey1, + }, + } + + fakeKubeClient := env.FakeKubeClient(WithObjects(secret)) cache := &fakes.FakeCache{} ocmClient := NewClient(fakeKubeClient, cache) octx := fakeocm.NewFakeOCMContext()