Skip to content

Commit

Permalink
fix: return the last verified version that fits the constraint (#574)
Browse files Browse the repository at this point in the history
Fixes open-component-model/ocm-project#336

---------

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
Co-authored-by: Frederic Wilhelm <frederic.wilhelm@sap.com>
  • Loading branch information
Skarlso and frewilhelm authored Jan 17, 2025
1 parent 8588071 commit 287a715
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 10 deletions.
9 changes: 3 additions & 6 deletions e2e/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/ocm/fakes/fakes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
13 changes: 11 additions & 2 deletions pkg/ocm/ocm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
}
Expand All @@ -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
}
}
Expand All @@ -462,6 +470,7 @@ type Version struct {
}

func (c *Client) ListComponentVersions(
_ context.Context,
logger logr.Logger,
octx ocm.Context,
obj *v1alpha1.ComponentVersion,
Expand Down
74 changes: 73 additions & 1 deletion pkg/ocm/ocm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit 287a715

Please sign in to comment.