diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index 2937b701..b0aaede5 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -550,7 +550,15 @@ func validateRegistryScopeFormat(scope string) error { // https://github.com/distribution/distribution/blob/main/reference/regexp.go#L31 domainRegexp := regexp.MustCompile(`^(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?$`) repositoryRegexp := regexp.MustCompile(`^[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$`) - errorMessage := "registry scope %q is not valid, make sure it is a fully qualified registry URL without the scheme/protocol, e.g domain.com/my/repository OR a local trust policy scope, e.g local/myOCILayout" + ensureMessage := "make sure it is a fully qualified repository without the scheme, protocol or tag. For example domain.com/my/repository or a local scope like local/myOCILayout" + errorMessage := "registry scope %q is not valid, " + ensureMessage + errorWildCardMessage := "registry scope %q with wild card(s) is not valid, " + ensureMessage + + // Check for presence of * in scope + if len(scope) > 1 && strings.Contains(scope, "*") { + return fmt.Errorf(errorWildCardMessage, scope) + } + domain, repository, found := strings.Cut(scope, "/") if !found { return fmt.Errorf(errorMessage, scope) diff --git a/verifier/trustpolicy/trustpolicy_test.go b/verifier/trustpolicy/trustpolicy_test.go index d3da1517..ead28cae 100644 --- a/verifier/trustpolicy/trustpolicy_test.go +++ b/verifier/trustpolicy/trustpolicy_test.go @@ -206,7 +206,21 @@ func TestInvalidRegistryScopes(t *testing.T) { policyStatement.RegistryScopes = []string{scope} policyDoc.TrustPolicies = []TrustPolicy{policyStatement} err := policyDoc.Validate() - if err == nil || err.Error() != "registry scope \""+scope+"\" is not valid, make sure it is a fully qualified registry URL without the scheme/protocol, e.g domain.com/my/repository OR a local trust policy scope, e.g local/myOCILayout" { + if err == nil || err.Error() != "registry scope \""+scope+"\" is not valid, make sure it is a fully qualified repository without the scheme, protocol or tag. For example domain.com/my/repository or a local scope like local/myOCILayout" { + t.Fatalf("invalid registry scope should return error. Error : %q", err) + } + } + + // Test invalid scope with wild card suffix + + invalidWildCardScopes := []string{"example.com/*", "*/", "example*/", "ex*test"} + for _, scope := range invalidWildCardScopes { + policyDoc := dummyPolicyDocument() + policyStatement := dummyPolicyStatement() + policyStatement.RegistryScopes = []string{scope} + policyDoc.TrustPolicies = []TrustPolicy{policyStatement} + err := policyDoc.Validate() + if err == nil || err.Error() != "registry scope \""+scope+"\" with wild card(s) is not valid, make sure it is a fully qualified repository without the scheme, protocol or tag. For example domain.com/my/repository or a local scope like local/myOCILayout" { t.Fatalf("invalid registry scope should return error. Error : %q", err) } } @@ -215,7 +229,7 @@ func TestInvalidRegistryScopes(t *testing.T) { // TestValidRegistryScopes tests valid scopes are accepted func TestValidRegistryScopes(t *testing.T) { validScopes := []string{ - "example.com/rep", "example.com:8080/rep/rep2", "example.com/rep/subrep/subsub", + "*", "example.com/rep", "example.com:8080/rep/rep2", "example.com/rep/subrep/subsub", "10.10.10.10:8080/rep/rep2", "domain/rep", "domain:1234/rep", }