Skip to content

Commit 472cc1b

Browse files
committed
Changes to verify package in preparation for move to library-go
The CVO verify package will be moved to library-go for reuse by 'oc adm release mirror' and CVO. Changes are being made here in CVO before the move to provide a cleaner move to library-go. Logic to create verifier was broken out into a new configmap method NewFromManifests. This method uses k8s encoding and as a result existing test cases had to be changed from creating manifests from from declarations within the test cases itself to creating them from config map files. In this manner the lib/Manifest object is properly created with its Raw bytes field populated.
1 parent 2b421c0 commit 472cc1b

File tree

14 files changed

+453
-232
lines changed

14 files changed

+453
-232
lines changed

pkg/cvo/cvo.go

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@ import (
1212

1313
"github.com/blang/semver/v4"
1414
"github.com/google/uuid"
15-
"github.com/pkg/errors"
1615
corev1 "k8s.io/api/core/v1"
1716
apierrors "k8s.io/apimachinery/pkg/api/errors"
1817
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19-
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2018
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2119
"k8s.io/apimachinery/pkg/util/wait"
2220
informerscorev1 "k8s.io/client-go/informers/core/v1"
@@ -281,32 +279,20 @@ func (optr *Operator) InitializeFromPayload(restConfig *rest.Config, burstRestCo
281279
// package for more details on the algorithm for verification. If the annotation is set, a verifier or error
282280
// is always returned.
283281
func loadConfigMapVerifierDataFromUpdate(update *payload.Update, clientBuilder sigstore.HTTPClient, configMapClient coreclientsetv1.ConfigMapsGetter) (verify.Interface, *verify.StorePersister, error) {
284-
configMapGVK := corev1.SchemeGroupVersion.WithKind("ConfigMap")
285-
for _, manifest := range update.Manifests {
286-
if manifest.GVK != configMapGVK {
287-
continue
288-
}
289-
if _, ok := manifest.Obj.GetAnnotations()[verify.ReleaseAnnotationConfigMapVerifier]; !ok {
290-
continue
291-
}
292-
src := fmt.Sprintf("the config map %s/%s", manifest.Obj.GetNamespace(), manifest.Obj.GetName())
293-
data, _, err := unstructured.NestedStringMap(manifest.Obj.Object, "data")
294-
if err != nil {
295-
return nil, nil, errors.Wrapf(err, "%s is not valid: %v", src, err)
296-
}
297-
verifier, err := verify.NewFromConfigMapData(src, data, clientBuilder)
298-
if err != nil {
299-
return nil, nil, err
300-
}
301-
302-
// allow the verifier to consult the cluster for signature data, and also configure
303-
// a process that writes signatures back to that store
304-
signatureStore := configmap.NewStore(configMapClient, nil)
305-
verifier.Store = &serial.Store{Stores: []store.Store{signatureStore, verifier.Store}}
306-
persister := verify.NewSignatureStorePersister(signatureStore, verifier)
307-
return verifier, persister, nil
282+
verifier, err := verify.NewFromManifests(update.Manifests, clientBuilder)
283+
if err != nil {
284+
return nil, nil, err
308285
}
309-
return nil, nil, nil
286+
if verifier == nil {
287+
return nil, nil, nil
288+
}
289+
290+
// allow the verifier to consult the cluster for signature data, and also configure
291+
// a process that writes signatures back to that store
292+
signatureStore := configmap.NewStore(configMapClient, nil)
293+
verifier.Store = &serial.Store{Stores: []store.Store{signatureStore, verifier.Store}}
294+
persister := verify.NewSignatureStorePersister(signatureStore, verifier)
295+
return verifier, persister, nil
310296
}
311297

312298
// Run runs the cluster version operator until stopCh is completed. Workers is ignored for now.

pkg/cvo/cvo_test.go

Lines changed: 69 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cvo
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
67
"io/ioutil"
@@ -20,7 +21,6 @@ import (
2021
apiextclientv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
2122
"k8s.io/apimachinery/pkg/api/errors"
2223
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23-
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2424
"k8s.io/apimachinery/pkg/labels"
2525
"k8s.io/apimachinery/pkg/runtime"
2626
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -3272,190 +3272,97 @@ func fakeClientsetWithUpdates(obj *configv1.ClusterVersion) *fake.Clientset {
32723272
}
32733273

32743274
func Test_loadReleaseVerifierFromConfigMap(t *testing.T) {
3275-
redhatData, err := ioutil.ReadFile(filepath.Join("..", "verify", "testdata", "keyrings", "redhat.txt"))
3276-
if err != nil {
3277-
t.Fatal(err)
3278-
}
3275+
const (
3276+
ExpectedError = "the config map openshift-config-managed/release-verification did not provide any signature stores to read from and cannot be used"
3277+
ExpectedVerifier = "All release image digests must have GPG signatures from verifier-public-key-redhat (567E347AD0044ADE55BA8A5F199E2F91FD431D51: Red Hat, Inc. (release key 2) <[email protected]>) - will check for signatures in containers/image format at serial signature store wrapping config maps in openshift-config-managed with label \"release.openshift.io/verification-signatures\", parallel signature store wrapping file:///verify/testdata/signatures"
3278+
)
32793279

32803280
tests := []struct {
3281-
name string
3282-
update *payload.Update
3283-
want bool
3284-
wantErr bool
3285-
wantVerifiers int
3281+
name string
3282+
fileName string
3283+
update *payload.Update
3284+
expectedError string
3285+
expectedVerifier string
3286+
expectStore bool
32863287
}{
32873288
{
3288-
name: "is a no-op when no objects are found",
3289-
update: &payload.Update{},
3289+
name: "is a no-op when no objects are found",
3290+
fileName: "",
3291+
update: &payload.Update{},
32903292
},
32913293
{
3292-
name: "requires data",
3293-
update: &payload.Update{
3294-
Manifests: []lib.Manifest{
3295-
{
3296-
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
3297-
Obj: &unstructured.Unstructured{
3298-
Object: map[string]interface{}{
3299-
"metadata": map[string]interface{}{
3300-
"name": "release-verification",
3301-
"namespace": "openshift-config-managed",
3302-
"annotations": map[string]interface{}{
3303-
"release.openshift.io/verification-config-map": "",
3304-
},
3305-
},
3306-
},
3307-
},
3308-
},
3309-
},
3310-
},
3311-
wantErr: true,
3294+
name: "requires data",
3295+
fileName: "requires-data.yaml",
3296+
update: &payload.Update{},
3297+
expectedError: ExpectedError,
33123298
},
33133299
{
3314-
name: "requires stores",
3315-
update: &payload.Update{
3316-
Manifests: []lib.Manifest{
3317-
{
3318-
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
3319-
Obj: &unstructured.Unstructured{
3320-
Object: map[string]interface{}{
3321-
"metadata": map[string]interface{}{
3322-
"name": "verification",
3323-
"namespace": "openshift-config",
3324-
"annotations": map[string]interface{}{
3325-
"release.openshift.io/verification-config-map": "",
3326-
},
3327-
},
3328-
"data": map[string]interface{}{
3329-
"verifier-public-key-redhat": string(redhatData),
3330-
},
3331-
},
3332-
},
3333-
},
3334-
},
3335-
},
3336-
wantErr: true,
3300+
name: "requires stores",
3301+
fileName: "requires-stores.yaml",
3302+
update: &payload.Update{},
3303+
expectedError: ExpectedError,
33373304
},
33383305
{
3339-
name: "requires verifiers",
3340-
update: &payload.Update{
3341-
Manifests: []lib.Manifest{
3342-
{
3343-
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
3344-
Obj: &unstructured.Unstructured{
3345-
Object: map[string]interface{}{
3346-
"metadata": map[string]interface{}{
3347-
"name": "release-verification",
3348-
"namespace": "openshift-config-managed",
3349-
"annotations": map[string]interface{}{
3350-
"release.openshift.io/verification-config-map": "",
3351-
},
3352-
},
3353-
"data": map[string]interface{}{
3354-
"store-local": "file://../verify/testdata/signatures",
3355-
},
3356-
},
3357-
},
3358-
},
3359-
},
3360-
},
3361-
wantErr: true,
3306+
name: "requires verifiers",
3307+
fileName: "requires-verifiers.yaml",
3308+
update: &payload.Update{},
3309+
expectedError: ExpectedError,
33623310
},
33633311
{
3364-
name: "loads valid configuration",
3365-
update: &payload.Update{
3366-
Manifests: []lib.Manifest{
3367-
{
3368-
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
3369-
Obj: &unstructured.Unstructured{
3370-
Object: map[string]interface{}{
3371-
"metadata": map[string]interface{}{
3372-
"name": "release-verification",
3373-
"namespace": "openshift-config-managed",
3374-
"annotations": map[string]interface{}{
3375-
"release.openshift.io/verification-config-map": "",
3376-
},
3377-
},
3378-
"data": map[string]interface{}{
3379-
"verifier-public-key-redhat": string(redhatData),
3380-
"store-local": "file://../verify/testdata/signatures",
3381-
},
3382-
},
3383-
},
3384-
},
3385-
},
3386-
},
3387-
want: true,
3388-
wantVerifiers: 1,
3312+
name: "loads valid configuration",
3313+
fileName: "loads-valid.yaml",
3314+
update: &payload.Update{},
3315+
expectedVerifier: ExpectedVerifier,
3316+
expectStore: true,
33893317
},
33903318
{
3391-
name: "only the first valid configuration is used",
3392-
update: &payload.Update{
3393-
Manifests: []lib.Manifest{
3394-
{
3395-
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
3396-
Obj: &unstructured.Unstructured{
3397-
Object: map[string]interface{}{
3398-
"metadata": map[string]interface{}{
3399-
"name": "release-verification",
3400-
"namespace": "openshift-config-managed",
3401-
"annotations": map[string]interface{}{
3402-
"release.openshift.io/verification-config-map": "",
3403-
},
3404-
},
3405-
"data": map[string]interface{}{
3406-
"verifier-public-key-redhat": string(redhatData),
3407-
"store-local": "\nfile://../verify/testdata/signatures\n",
3408-
},
3409-
},
3410-
},
3411-
},
3412-
{
3413-
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
3414-
Obj: &unstructured.Unstructured{
3415-
Object: map[string]interface{}{
3416-
"metadata": map[string]interface{}{
3417-
"name": "release-verificatio-2n",
3418-
"namespace": "openshift-config-managed",
3419-
"annotations": map[string]interface{}{
3420-
"release.openshift.io/verification-config-map": "",
3421-
},
3422-
},
3423-
"data": map[string]interface{}{
3424-
"verifier-public-key-redhat": string(redhatData),
3425-
"verifier-public-key-redhat-2": string(redhatData),
3426-
"store-local": "file://../verify/testdata/signatures",
3427-
},
3428-
},
3429-
},
3430-
},
3431-
},
3432-
},
3433-
want: true,
3434-
wantVerifiers: 1,
3319+
name: "only the first valid configuration is used",
3320+
fileName: "only-first-used.yaml",
3321+
update: &payload.Update{},
3322+
expectedVerifier: ExpectedVerifier,
3323+
expectStore: true,
34353324
},
34363325
}
34373326
for _, tt := range tests {
3327+
if tt.fileName != "" {
3328+
raw, err := ioutil.ReadFile(filepath.Join("..", "verify", "testdata", "manifests", tt.fileName))
3329+
if err != nil {
3330+
t.Fatal(err)
3331+
}
3332+
ms, err := lib.ParseManifests(bytes.NewReader(raw))
3333+
if err != nil {
3334+
t.Fatalf("failed to parse file %s as a manifest, error = %v", tt.fileName, err)
3335+
}
3336+
tt.update.Manifests = ms
3337+
}
34383338
t.Run(tt.name, func(t *testing.T) {
34393339
f := kfake.NewSimpleClientset()
34403340
got, store, err := loadConfigMapVerifierDataFromUpdate(tt.update, sigstore.DefaultClient, f.CoreV1())
3441-
if (err != nil) != tt.wantErr {
3442-
t.Fatalf("loadReleaseVerifierFromPayload() error = %v, wantErr %v", err, tt.wantErr)
3443-
}
3444-
if (got != nil) != tt.want {
3445-
t.Fatal(got)
3446-
}
3447-
if tt.want && store == nil {
3448-
t.Fatalf("expected valid store")
3449-
}
3450-
if err != nil {
3451-
return
3341+
if err == nil {
3342+
if tt.expectedError != "" {
3343+
t.Fatalf("loadReleaseVerifierFromPayload succeeded when we expected error \"%s\"", tt.expectedError)
3344+
}
3345+
} else if tt.expectedError == "" {
3346+
t.Fatalf("loadReleaseVerifierFromPayload failed when we expected success: %v", err)
3347+
} else if tt.expectedError != err.Error() {
3348+
t.Fatalf("loadReleaseVerifierFromPayload failed with \"%v\" (expected \"%s\")", err, tt.expectedError)
34523349
}
3350+
34533351
if got == nil {
3454-
return
3352+
if tt.expectedVerifier != "" {
3353+
t.Fatalf("loadReleaseVerifierFromPayload did not return a verifier when expected")
3354+
}
3355+
} else if tt.expectedVerifier == "" {
3356+
t.Fatalf("loadReleaseVerifierFromPayload returned a verifer when not expected")
3357+
} else {
3358+
rvString := got.(*verify.ReleaseVerifier).String()
3359+
if rvString != tt.expectedVerifier {
3360+
t.Fatalf("loadReleaseVerifierFromPayload returned \"%v\" when we expected \"%v\"", rvString, tt.expectedVerifier)
3361+
}
34553362
}
3456-
rv := got.(*verify.ReleaseVerifier)
3457-
if len(rv.Verifiers()) != tt.wantVerifiers {
3458-
t.Fatalf("unexpected release verifier: %#v", rv)
3363+
3364+
if tt.expectStore && store == nil {
3365+
t.Fatalf("loadReleaseVerifierFromPayload did not return a store when expected")
34593366
}
34603367
})
34613368
}

0 commit comments

Comments
 (0)