Add tests for keyless verification

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
This commit is contained in:
Stefan Prodan 2022-09-22 12:01:24 +03:00
parent b5ffc9fc65
commit 3b637a82fe
No known key found for this signature in database
GPG Key ID: 3299AEB0E4085BAF
2 changed files with 75 additions and 4 deletions

View File

@ -419,9 +419,12 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
} else if !obj.GetArtifact().HasRevision(revision) ||
conditions.GetObservedGeneration(obj, sourcev1.SourceVerifiedCondition) != obj.Generation ||
conditions.IsFalse(obj, sourcev1.SourceVerifiedCondition) {
provider := obj.Spec.Verify.Provider
err := r.verifyOCISourceSignature(ctx, obj, url, keychain)
if err != nil {
provider := obj.Spec.Verify.Provider
if obj.Spec.Verify.SecretRef == nil {
provider = fmt.Sprintf("%s keyless", provider)
}
e := serror.NewGeneric(
fmt.Errorf("failed to verify the signature using provider '%s': %w", provider, err),
sourcev1.VerificationError,
@ -570,7 +573,7 @@ func (r *OCIRepositoryReconciler) verifyOCISourceSignature(ctx context.Context,
}
// if no secret is provided, try keyless verification
ctrl.LoggerFrom(ctx).Info("no secret reference is provided, trying to verify the image using keyless approach")
ctrl.LoggerFrom(ctx).Info("no secret reference is provided, trying to verify the image using keyless method")
verifier, err := soci.NewVerifier(ctxTimeout, defaultCosignOciOpts...)
if err != nil {
return err

View File

@ -1029,6 +1029,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
wantErr bool
wantErrMsg string
shouldSign bool
keyless bool
beforeFunc func(obj *sourcev1.OCIRepository)
assertConditions []metav1.Condition
}{
{
@ -1060,6 +1062,64 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "failed to verify the signature using provider '<provider>': no matching signatures were found for '<url>'"),
},
},
{
name: "unsigned image should not pass keyless verification",
reference: &sourcev1.OCIRepositoryRef{
Tag: "6.1.5",
},
digest: img5.digest.Hex,
wantErr: true,
want: sreconcile.ResultEmpty,
keyless: true,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReconcilingCondition, "NewRevision", "new digest '<digest>' for '<url>'"),
*conditions.TrueCondition(sourcev1.ArtifactOutdatedCondition, "NewRevision", "new digest '<digest>' for '<url>'"),
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "failed to verify the signature using provider '<provider> keyless': no matching signatures"),
},
},
{
name: "verify failed before, removed from spec, remove condition",
reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"},
digest: img4.digest.Hex,
beforeFunc: func(obj *sourcev1.OCIRepository) {
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, "VerifyFailed", "fail msg")
obj.Spec.Verify = nil
obj.Status.Artifact = &sourcev1.Artifact{Revision: img4.digest.Hex}
},
want: sreconcile.ResultSuccess,
},
{
name: "same artifact, verified before, change in obj gen verify again",
reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"},
digest: img4.digest.Hex,
shouldSign: true,
beforeFunc: func(obj *sourcev1.OCIRepository) {
obj.Status.Artifact = &sourcev1.Artifact{Revision: img4.digest.Hex}
// Set Verified with old observed generation and different reason/message.
conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified")
// Set new object generation.
obj.SetGeneration(3)
},
want: sreconcile.ResultSuccess,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of digest <digest>"),
},
},
{
name: "no verify for already verified, verified condition remains the same",
reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"},
digest: img4.digest.Hex,
shouldSign: true,
beforeFunc: func(obj *sourcev1.OCIRepository) {
// Artifact present and custom verified condition reason/message.
obj.Status.Artifact = &sourcev1.Artifact{Revision: img4.digest.Hex}
conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified")
},
want: sreconcile.ResultSuccess,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, "Verified", "verified"),
},
},
}
builder := fakeclient.NewClientBuilder().WithScheme(testEnv.GetScheme())
@ -1102,13 +1162,17 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
Spec: sourcev1.OCIRepositorySpec{
URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost),
Verify: &sourcev1.OCIRepositoryVerification{
Provider: "cosign",
SecretRef: &meta.LocalObjectReference{Name: "cosign-key"}},
Provider: "cosign",
},
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
},
}
if !tt.keyless {
obj.Spec.Verify.SecretRef = &meta.LocalObjectReference{Name: "cosign-key"}
}
if tt.reference != nil {
obj.Spec.Reference = tt.reference
}
@ -1147,6 +1211,10 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
assertConditions[k].Message = strings.ReplaceAll(assertConditions[k].Message, "<provider>", "cosign")
}
if tt.beforeFunc != nil {
tt.beforeFunc(obj)
}
artifact := &sourcev1.Artifact{}
got, err := r.reconcileSource(ctx, obj, artifact, tmpDir)
if tt.wantErr {