Repository: deislabs/ratify (go)

Issue:
mutation fails for dockerhub images that do not specify docker.io registry
**What steps did you take and what happened:**
[A clear and concise description of what the bug is.]

```
$ kubectl run nginx --image=nginx:latest
Error from server: admission webhook "mutation.gatekeeper.sh" denied the request: failed to resolve external data placeholders: failed to retrieve external data item from provider ratify-mutation-provider: failed to mutate image reference nginx:latest: invalid reference: missing repository
```


works as expected given the full path:
```
kubectl run nginx --image=docker.io/library/nginx:latest
Error from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request: [ratify-constraint] Subject failed verification: docker.io/library/nginx@sha256:b8f2383a95879e1ae064940d9a200f67a6c79e710ed82ac42263397367e7cc4e
```

**What did you expect to happen:**


**Anything else you would like to add:**
[Miscellaneous information that will assist in solving the issue.]


**Environment:**

- Ratify version: (use the image tag):
- Kubernetes version: (use `kubectl version`):


Pull request description:
fix: add docker domain prefix as default
# Description

## What this PR does / why we need it:
- Adds `docker.io/library` prefix if domain not present in subject reference
- This is consistent with expected behavior from Docker and other derived tooling
- Add unit tests

## Which issue(s) this PR fixes *(optional, using `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when the PR gets merged)*:
Fixes #591

## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Please also list any relevant details for your test configuration

- [x] Unit tests
- [ ] e2e-tests

# Checklist:

- [ ] Does the affected code have corresponding tests?
- [ ] Are the changes documented, not just with inline documentation, but also with conceptual documentation such as an overview of a new feature, or task-based documentation like a tutorial? Consider if this change should be announced on your project blog.
- [ ] Does this introduce breaking changes that would require an announcement or bumping the major version?
- [ ] Do all new files have appropriate license header?


Patch:
diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go
index 704adf7..ba8cdab 100644
--- a/pkg/utils/utils.go
+++ b/pkg/utils/utils.go
@@ -25,11 +25,13 @@ import (
 	"github.com/opencontainers/go-digest"
 )
 
+const defaultRegistryPrefix = "docker.io/library/"
+
 // ParseDigest parses the given string and returns a validated Digest object.
 func ParseDigest(digestStr string) (digest.Digest, error) {
 	digest, err := digest.Parse(digestStr)
 	if err != nil {
-		return "", fmt.Errorf("The digest of the subject is invalid %s: %w", digestStr, err)
+		return "", fmt.Errorf("the digest of the subject is invalid %s: %w", digestStr, err)
 	}
 
 	return digest, nil
@@ -45,6 +47,10 @@ func ParseSubjectReference(subRef string) (common.Reference, error) {
 	var subjectRef common.Reference
 	if named, ok := parseResult.(reference.Named); ok {
 		subjectRef.Path = named.Name()
+		if reference.Domain(named) == "" {
+			subRef = fmt.Sprint(defaultRegistryPrefix, subRef)
+			subjectRef.Path = fmt.Sprint(defaultRegistryPrefix, subjectRef.Path)
+		}
 	} else {
 		return common.Reference{}, fmt.Errorf("failed to parse subject reference Path")
 	}


Test patch:
diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go
index 02f1019..c877500 100644
--- a/pkg/utils/utils_test.go
+++ b/pkg/utils/utils_test.go
@@ -45,6 +45,7 @@ func TestParseSubjectReference_ReturnsExpected(t *testing.T) {
 	testcases := []struct {
 		input          string
 		output         common.Reference
+		isDefaultTest  bool
 		expectedErrMsg string
 	}{
 		{
@@ -58,9 +59,10 @@ func TestParseSubjectReference_ReturnsExpected(t *testing.T) {
 		{
 			input: "net-monitor@sha256:a0fc570a245b09ed752c42d600ee3bb5b4f77bbd70d8898780b7ab43454530eb",
 			output: common.Reference{
-				Path:   "net-monitor",
+				Path:   "docker.io/library/net-monitor",
 				Digest: getDigest("sha256:a0fc570a245b09ed752c42d600ee3bb5b4f77bbd70d8898780b7ab43454530eb"),
 			},
+			isDefaultTest: true,
 		},
 		{
 			input:          "/localhost:5000/net-monitor:v1@sha256:a0fc570a245b09ed752c42d600ee3bb5b4f77bbd70d8898780b7ab43454530eb",
@@ -91,7 +93,7 @@ func TestParseSubjectReference_ReturnsExpected(t *testing.T) {
 				t.Fatalf("parsing subject reference expected to fail with err %v actual %v", testcase.expectedErrMsg, err)
 			}
 		} else {
-			if actual.Original != testcase.input {
+			if !testcase.isDefaultTest && actual.Original != testcase.input {
 				t.Fatalf("parsing subject reference failed expected original %v actual %v", testcase.input, actual.Original)
 			}