Skip to content

Commit c3a89f4

Browse files
refactor(notation): move outcome checker to own func
Signed-off-by: Jason <[email protected]>
1 parent 340d4ce commit c3a89f4

File tree

3 files changed

+143
-23
lines changed

3 files changed

+143
-23
lines changed

internal/controller/ocirepository_controller.go

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -437,26 +437,16 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
437437

438438
result, err := r.verifySignature(ctx, obj, ref, keychain, auth, opts...)
439439
if err != nil {
440-
if result == soci.VerificationResultFailed {
441-
provider := obj.Spec.Verify.Provider
442-
if obj.Spec.Verify.SecretRef == nil && obj.Spec.Verify.Provider == "cosign" {
443-
provider = fmt.Sprintf("%s keyless", provider)
444-
}
445-
e := serror.NewGeneric(
446-
fmt.Errorf("failed to verify the signature using provider '%s': %w", provider, err),
447-
sourcev1.VerificationError,
448-
)
449-
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, e.Err.Error())
450-
return sreconcile.ResultEmpty, e
451-
}
452-
453-
if result == soci.VerificationResultIgnored {
454-
r.eventLogf(ctx, obj, corev1.EventTypeWarning, sourcev1.VerificationError,
455-
"validation ignored for '%s' with message: %s", ref, err)
440+
provider := obj.Spec.Verify.Provider
441+
if obj.Spec.Verify.SecretRef == nil && obj.Spec.Verify.Provider == "cosign" {
442+
provider = fmt.Sprintf("%s keyless", provider)
456443
}
457-
} else if result == soci.VerificationResultIgnored {
458-
r.eventLogf(ctx, obj, corev1.EventTypeWarning, sourcev1.VerificationError,
459-
"validation ignored for '%s'", ref)
444+
e := serror.NewGeneric(
445+
fmt.Errorf("failed to verify the signature using provider '%s': %w", provider, err),
446+
sourcev1.VerificationError,
447+
)
448+
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, e.Err.Error())
449+
return sreconcile.ResultEmpty, e
460450
}
461451

462452
if result == soci.VerificationResultSuccess {

internal/oci/notation/notation.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,18 @@ func (v *NotationVerifier) Verify(ctx context.Context, ref name.Reference) (oci.
236236
return oci.VerificationResultFailed, err
237237
}
238238

239+
return v.checkOutcome(outcomes, url)
240+
}
241+
242+
// checkOutcome checks the verification outcomes for a given URL and returns the corresponding OCI verification result.
243+
// It takes a slice of verification outcomes and a URL as input parameters.
244+
// If there are no verification outcomes, it returns a failed verification result with an error message.
245+
// If the first verification outcome has a verification level of "trustpolicy.LevelSkip", it returns an ignored verification result.
246+
// If any of the verification results have an error, it logs the error message and sets the "ignore" flag to true if the error type is "trustpolicy.TypeAuthenticity".
247+
// If the "ignore" flag is true, it returns an ignored verification result.
248+
// Otherwise, it returns a successful verification result.
249+
// The function returns the OCI verification result and an error, if any.
250+
func (v *NotationVerifier) checkOutcome(outcomes []*notation.VerificationOutcome, url string) (oci.VerificationResult, error) {
239251
if len(outcomes) == 0 {
240252
return oci.VerificationResultFailed, fmt.Errorf("signature verification failed for all the signatures associated with %s", url)
241253
}
@@ -246,18 +258,22 @@ func (v *NotationVerifier) Verify(ctx context.Context, ref name.Reference) (oci.
246258
return oci.VerificationResultIgnored, nil
247259
}
248260

261+
ignore := false
262+
249263
for _, i := range outcome.VerificationResults {
250264
if i.Error != nil {
251265
if i.Type == trustpolicy.TypeAuthenticity {
252-
return oci.VerificationResultIgnored, i.Error
266+
ignore = true
253267
}
254268

255-
if i.Action == trustpolicy.ActionLog {
256-
v.logger.Info(fmt.Sprintf("verification check for type %s failed for %s with message %s", i.Type, url, i.Error.Error()))
257-
}
269+
v.logger.Info(fmt.Sprintf("verification check for type %s failed for %s with message %s", i.Type, url, i.Error.Error()))
258270
}
259271
}
260272

273+
if ignore {
274+
return oci.VerificationResultIgnored, nil
275+
}
276+
261277
return oci.VerificationResultSuccess, nil
262278
}
263279

internal/oci/notation/notation_test.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@ limitations under the License.
1717
package notation
1818

1919
import (
20+
"fmt"
2021
"net/http"
2122
"reflect"
2223
"testing"
2324

2425
"github.com/go-logr/logr"
2526
"github.com/google/go-containerregistry/pkg/authn"
2627
"github.com/google/go-containerregistry/pkg/v1/remote"
28+
"github.com/notaryproject/notation-go"
2729
"github.com/notaryproject/notation-go/verifier/trustpolicy"
2830
. "github.com/onsi/gomega"
31+
32+
"github.com/fluxcd/source-controller/internal/oci"
2933
)
3034

3135
func TestOptions(t *testing.T) {
@@ -351,6 +355,116 @@ func TestCleanTrustPolicy(t *testing.T) {
351355
}
352356
}
353357

358+
func TestOutcomeChecker(t *testing.T) {
359+
g := NewWithT(t)
360+
361+
testCases := []struct {
362+
name string
363+
outcome []*notation.VerificationOutcome
364+
wantErr bool
365+
errMessage string
366+
logMessage []string
367+
verificationResult oci.VerificationResult
368+
}{
369+
{
370+
name: "no outcome failed with error message",
371+
verificationResult: oci.VerificationResultFailed,
372+
wantErr: true,
373+
errMessage: "signature verification failed for all the signatures associated with example.com/podInfo",
374+
},
375+
{
376+
name: "verification result ignored with log message",
377+
outcome: []*notation.VerificationOutcome{
378+
{
379+
VerificationLevel: trustpolicy.LevelAudit,
380+
VerificationResults: []*notation.ValidationResult{
381+
{
382+
Type: trustpolicy.TypeAuthenticity,
383+
Action: trustpolicy.ActionLog,
384+
Error: fmt.Errorf("123"),
385+
},
386+
},
387+
},
388+
},
389+
verificationResult: oci.VerificationResultIgnored,
390+
logMessage: []string{"verification check for type authenticity failed for example.com/podInfo with message 123"},
391+
},
392+
{
393+
name: "verification result ignored with no log message (skip)",
394+
outcome: []*notation.VerificationOutcome{
395+
{
396+
VerificationLevel: trustpolicy.LevelSkip,
397+
VerificationResults: []*notation.ValidationResult{},
398+
},
399+
},
400+
verificationResult: oci.VerificationResultIgnored,
401+
},
402+
{
403+
name: "verification result success with log message",
404+
outcome: []*notation.VerificationOutcome{
405+
{
406+
VerificationLevel: trustpolicy.LevelAudit,
407+
VerificationResults: []*notation.ValidationResult{
408+
{
409+
Type: trustpolicy.TypeAuthenticTimestamp,
410+
Action: trustpolicy.ActionLog,
411+
Error: fmt.Errorf("456"),
412+
},
413+
{
414+
Type: trustpolicy.TypeExpiry,
415+
Action: trustpolicy.ActionLog,
416+
Error: fmt.Errorf("789"),
417+
},
418+
},
419+
},
420+
},
421+
verificationResult: oci.VerificationResultSuccess,
422+
logMessage: []string{
423+
"verification check for type authenticTimestamp failed for example.com/podInfo with message 456",
424+
"verification check for type expiry failed for example.com/podInfo with message 789",
425+
},
426+
},
427+
{
428+
name: "verification result success with no log message",
429+
outcome: []*notation.VerificationOutcome{
430+
{
431+
VerificationLevel: trustpolicy.LevelAudit,
432+
VerificationResults: []*notation.ValidationResult{},
433+
},
434+
},
435+
verificationResult: oci.VerificationResultSuccess,
436+
},
437+
}
438+
439+
// Run the test cases
440+
for _, tc := range testCases {
441+
t.Run(tc.name, func(t *testing.T) {
442+
l := &testLogger{[]string{}, logr.RuntimeInfo{CallDepth: 1}}
443+
logger := logr.New(l)
444+
445+
v := NotationVerifier{
446+
logger: logger,
447+
}
448+
449+
result, err := v.checkOutcome(tc.outcome, "example.com/podInfo")
450+
451+
if tc.wantErr {
452+
g.Expect(err).ToNot(BeNil())
453+
g.Expect(err.Error()).Should(Equal(tc.errMessage))
454+
} else {
455+
g.Expect(err).To(BeNil())
456+
}
457+
458+
g.Expect(result).Should(Equal(tc.verificationResult))
459+
g.Expect(len(l.Output)).Should(Equal(len(tc.logMessage)))
460+
461+
for i, j := range tc.logMessage {
462+
g.Expect(l.Output[i]).Should(Equal(j))
463+
}
464+
})
465+
}
466+
}
467+
354468
func dummyPolicyDocument() (policyDoc *trustpolicy.Document) {
355469
policyDoc = &trustpolicy.Document{
356470
Version: "1.0",

0 commit comments

Comments
 (0)