diff --git a/pkg/customresources/verifiers/api.go b/pkg/customresources/verifiers/api.go new file mode 100644 index 000000000..b1e492c38 --- /dev/null +++ b/pkg/customresources/verifiers/api.go @@ -0,0 +1,32 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package verifiers + +import ( + vr "github.com/deislabs/ratify/pkg/verifier" +) + +type Verifiers interface { + GetVerifiers(scope string) []vr.ReferenceVerifier + + AddVerifier(scope, verifierName string, verifier vr.ReferenceVerifier) + + DeleteVerifier(scope, verifierName string) + + IsEmpty() bool + + GetVerifierCount() int +} diff --git a/pkg/customresources/verifiers/verifiers.go b/pkg/customresources/verifiers/verifiers.go new file mode 100644 index 000000000..d0ef99d6a --- /dev/null +++ b/pkg/customresources/verifiers/verifiers.go @@ -0,0 +1,75 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package verifiers + +import ( + "github.com/deislabs/ratify/internal/constants" + vr "github.com/deislabs/ratify/pkg/verifier" +) + +type ActiveVerifiers struct { + NamespacedVerifiers map[string]map[string]vr.ReferenceVerifier +} + +func NewActiveVerifiers() ActiveVerifiers { + return ActiveVerifiers{ + NamespacedVerifiers: make(map[string]map[string]vr.ReferenceVerifier), + } +} + +// GetVerifiers implements the Verifiers interface. +// It returns a list of verifiers for the given scope. If no verifiers are found for the given scope, it returns cluster-wide verifiers. +func (v *ActiveVerifiers) GetVerifiers(scope string) []vr.ReferenceVerifier { + verifiers := []vr.ReferenceVerifier{} + for _, verifier := range v.NamespacedVerifiers[scope] { + verifiers = append(verifiers, verifier) + } + + if len(verifiers) == 0 && scope != constants.EmptyNamespace { + for _, verifier := range v.NamespacedVerifiers[constants.EmptyNamespace] { + verifiers = append(verifiers, verifier) + } + } + return verifiers +} + +func (v *ActiveVerifiers) AddVerifier(scope, verifierName string, verifier vr.ReferenceVerifier) { + if _, ok := v.NamespacedVerifiers[scope]; !ok { + v.NamespacedVerifiers[scope] = make(map[string]vr.ReferenceVerifier) + } + v.NamespacedVerifiers[scope][verifierName] = verifier +} + +func (v *ActiveVerifiers) DeleteVerifier(scope, verifierName string) { + if verifiers, ok := v.NamespacedVerifiers[scope]; ok { + delete(verifiers, verifierName) + if len(verifiers) == 0 { + delete(v.NamespacedVerifiers, scope) + } + } +} + +func (v *ActiveVerifiers) IsEmpty() bool { + return len(v.NamespacedVerifiers) == 0 +} + +func (v *ActiveVerifiers) GetVerifierCount() int { + count := 0 + for _, verifiers := range v.NamespacedVerifiers { + count += len(verifiers) + } + return count +} diff --git a/pkg/customresources/verifiers/verifiers_test.go b/pkg/customresources/verifiers/verifiers_test.go new file mode 100644 index 000000000..24d44c912 --- /dev/null +++ b/pkg/customresources/verifiers/verifiers_test.go @@ -0,0 +1,105 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package verifiers + +import ( + "context" + "testing" + + "github.com/deislabs/ratify/internal/constants" + "github.com/deislabs/ratify/pkg/common" + "github.com/deislabs/ratify/pkg/ocispecs" + "github.com/deislabs/ratify/pkg/referrerstore" + "github.com/deislabs/ratify/pkg/verifier" +) + +type mockVerifier struct { + name string +} + +func (v mockVerifier) Name() string { + return v.name +} + +func (v mockVerifier) Type() string { + return "mockType" +} + +func (v mockVerifier) CanVerify(_ context.Context, _ ocispecs.ReferenceDescriptor) bool { + return true +} + +func (v mockVerifier) Verify(_ context.Context, _ common.Reference, _ ocispecs.ReferenceDescriptor, _ referrerstore.ReferrerStore) (verifier.VerifierResult, error) { + return verifier.VerifierResult{}, nil +} + +func (v mockVerifier) GetNestedReferences() []string { + return nil +} + +const ( + namespace1 = constants.EmptyNamespace + namespace2 = "namespace2" + name1 = "name1" + name2 = "name2" +) + +var ( + verifier1 = mockVerifier{name: name1} + verifier2 = mockVerifier{name: name2} +) + +func TestVerifiersOperations(t *testing.T) { + verifiers := NewActiveVerifiers() + verifiers.AddVerifier(namespace1, verifier1.Name(), verifier1) + verifiers.AddVerifier(namespace1, verifier2.Name(), verifier2) + verifiers.AddVerifier(namespace2, verifier1.Name(), verifier1) + verifiers.AddVerifier(namespace2, verifier2.Name(), verifier2) + + if verifiers.IsEmpty() { + t.Error("Expected verifiers to not be empty") + } + + if verifiers.GetVerifierCount() != 4 { + t.Errorf("Expected 4 verifiers, got %d", verifiers.GetVerifierCount()) + } + + if len(verifiers.GetVerifiers(namespace1)) != 2 { + t.Errorf("Expected 2 verifiers, got %d", len(verifiers.GetVerifiers(namespace1))) + } + + if len(verifiers.GetVerifiers(namespace2)) != 2 { + t.Errorf("Expected 2 verifiers, got %d", len(verifiers.GetVerifiers(namespace2))) + } + + verifiers.DeleteVerifier(namespace2, verifier1.Name()) + verifiers.DeleteVerifier(namespace2, verifier2.Name()) + + if len(verifiers.GetVerifiers(namespace2)) != 2 { + t.Errorf("Expected 2 verifiers, got %d", len(verifiers.GetVerifiers(namespace2))) + } + + verifiers.DeleteVerifier(namespace1, verifier1.Name()) + verifiers.DeleteVerifier(namespace1, verifier2.Name()) + + if !verifiers.IsEmpty() { + t.Error("Expected verifiers to be empty") + } + + if verifiers.GetVerifierCount() != 0 { + t.Errorf("Expected 0 verifiers, got %d", verifiers.GetVerifierCount()) + } +} diff --git a/pkg/executor/core/executor.go b/pkg/executor/core/executor.go index 74a071d26..f1dea1cd4 100644 --- a/pkg/executor/core/executor.go +++ b/pkg/executor/core/executor.go @@ -37,6 +37,7 @@ import ( vr "github.com/deislabs/ratify/pkg/verifier" vt "github.com/deislabs/ratify/pkg/verifier/types" "golang.org/x/sync/errgroup" + ) const ( @@ -53,7 +54,7 @@ var logOpt = logger.Option{ type Executor struct { ReferrerStores []referrerstore.ReferrerStore PolicyEnforcer policyprovider.PolicyProvider - Verifiers []vr.ReferenceVerifier + Verifiers verifiers.Verifiers Config *config.ExecutorConfig }