@@ -9,105 +9,109 @@ import (
99 "github.com/stretchr/testify/assert"
1010)
1111
12- func TestValidateOCI_RealPackages (t * testing.T ) {
12+ func TestValidateOCI_RegistryAllowlist (t * testing.T ) {
1313 ctx := context .Background ()
1414
1515 tests := []struct {
16- name string
17- identifier string
18- serverName string
19- expectError bool
20- errorMessage string
21- skip bool
22- skipReason string
16+ name string
17+ identifier string
18+ expectError bool
19+ errorMsg string
2320 }{
21+ // Allowed registries - these should NOT fail with "unsupported registry"
22+ {
23+ name : "Docker Hub should be allowed" ,
24+ identifier : "docker.io/test/image:latest" ,
25+ // Will fail on image not found, but registry should be accepted
26+ expectError : true ,
27+ },
28+ {
29+ name : "Docker Hub without explicit registry should default and be allowed" ,
30+ identifier : "test/image:latest" ,
31+ // Will fail on image not found, but registry should be accepted
32+ expectError : true ,
33+ },
34+ {
35+ name : "GHCR should be allowed" ,
36+ identifier : "ghcr.io/test/image:latest" ,
37+ // Will fail on image fetch, but registry should be accepted
38+ expectError : true ,
39+ },
40+ {
41+ name : "Artifact Registry us-central1 should be allowed" ,
42+ identifier : "us-central1-docker.pkg.dev/project/repo/image:latest" ,
43+ // Will fail on image fetch, but registry should be accepted
44+ expectError : true ,
45+ },
46+ {
47+ name : "Artifact Registry europe-west1 should be allowed" ,
48+ identifier : "europe-west1-docker.pkg.dev/project/repo/image:latest" ,
49+ // Will fail on image fetch, but registry should be accepted
50+ expectError : true ,
51+ },
52+ {
53+ name : "Artifact Registry multi-region us should be allowed" ,
54+ identifier : "us-docker.pkg.dev/project/repo/image:latest" ,
55+ // Will fail on image fetch, but registry should be accepted
56+ expectError : true ,
57+ },
58+
59+ // Disallowed registries
2460 {
25- name : "empty package identifier should fail" ,
26- identifier : "" ,
27- serverName : "com.example/test" ,
28- expectError : true ,
29- errorMessage : "package identifier is required for OCI packages" ,
30- },
31- {
32- name : "real image with correct MCP annotation should pass (Docker Hub)" ,
33- identifier : "docker.io/domdomegg/airtable-mcp-server:1.7.2" ,
34- serverName : "io.github.domdomegg/airtable-mcp-server" ,
35- expectError : false ,
36- skip : true ,
37- skipReason : "Skipping to avoid hitting DockerHub rate limits in CI" ,
38- },
39- {
40- name : "GHCR image with correct MCP annotation should pass" ,
41- identifier : "ghcr.io/nkapila6/mcp-local-rag:latest" ,
42- serverName : "io.github.nkapila6/mcp-local-rag" ,
43- expectError : false ,
44- skip : true ,
45- skipReason : "Skipping to avoid network dependencies in CI" ,
46- },
47- {
48- name : "image without MCP annotation should fail" ,
49- identifier : "docker.io/library/nginx:latest" ,
50- serverName : "com.example/test" ,
51- expectError : true ,
52- errorMessage : "missing required annotation" ,
53- skip : true ,
54- skipReason : "Skipping to avoid hitting DockerHub rate limits in CI" ,
55- },
56- {
57- name : "non-existent image should fail" ,
58- identifier : "docker.io/nonexistent/doesnotexist:v99.99.99" ,
59- serverName : "com.example/test" ,
60- expectError : true ,
61- errorMessage : "not found" ,
62- skip : true ,
63- skipReason : "Skipping to avoid network dependencies in CI" ,
64- },
65- {
66- name : "Quay.io registry should be supported" ,
67- identifier : "quay.io/test/image:v1.0.0" ,
68- serverName : "com.example/test" ,
69- expectError : true , // Will fail because image doesn't exist, but registry should be accepted
70- errorMessage : "not found" ,
71- skip : true ,
72- skipReason : "Skipping to avoid network dependencies in CI" ,
73- },
74- {
75- name : "GCR registry should be supported" ,
76- identifier : "gcr.io/test/image:v1.0.0" ,
77- serverName : "com.example/test" ,
78- expectError : true , // Will fail because image doesn't exist, but registry should be accepted
79- errorMessage : "not found" ,
80- skip : true ,
81- skipReason : "Skipping to avoid network dependencies in CI" ,
82- },
83- {
84- name : "GitLab registry should be supported" ,
85- identifier : "registry.gitlab.com/test/image:v1.0.0" ,
86- serverName : "com.example/test" ,
87- expectError : true , // Will fail because image doesn't exist, but registry should be accepted
88- errorMessage : "not found" ,
89- skip : true ,
90- skipReason : "Skipping to avoid network dependencies in CI" ,
61+ name : "GCR should be rejected" ,
62+ identifier : "gcr.io/test/image:latest" ,
63+ expectError : true ,
64+ errorMsg : "unsupported OCI registry" ,
65+ },
66+ {
67+ name : "Quay.io should be rejected" ,
68+ identifier : "quay.io/test/image:latest" ,
69+ expectError : true ,
70+ errorMsg : "unsupported OCI registry" ,
71+ },
72+ {
73+ name : "ECR Public should be rejected" ,
74+ identifier : "public.ecr.aws/test/image:latest" ,
75+ expectError : true ,
76+ errorMsg : "unsupported OCI registry" ,
77+ },
78+ {
79+ name : "GitLab registry should be rejected" ,
80+ identifier : "registry.gitlab.com/test/image:latest" ,
81+ expectError : true ,
82+ errorMsg : "unsupported OCI registry" ,
83+ },
84+ {
85+ name : "Custom registry should be rejected" ,
86+ identifier : "custom-registry.com/test/image:latest" ,
87+ expectError : true ,
88+ errorMsg : "unsupported OCI registry" ,
89+ },
90+ {
91+ name : "Harbor registry should be rejected" ,
92+ identifier : "harbor.example.com/test/image:latest" ,
93+ expectError : true ,
94+ errorMsg : "unsupported OCI registry" ,
9195 },
9296 }
9397
9498 for _ , tt := range tests {
9599 t .Run (tt .name , func (t * testing.T ) {
96- if tt .skip {
97- t .Skip (tt .skipReason )
98- }
99-
100100 pkg := model.Package {
101101 RegistryType : model .RegistryTypeOCI ,
102102 Identifier : tt .identifier ,
103103 }
104104
105- err := registries .ValidateOCI (ctx , pkg , tt . serverName )
105+ err := registries .ValidateOCI (ctx , pkg , "com.example/test" )
106106
107107 if tt .expectError {
108108 assert .Error (t , err )
109- if tt .errorMessage != "" {
110- assert .Contains (t , err .Error (), tt .errorMessage )
109+ if tt .errorMsg != "" {
110+ // Should contain the specific error message
111+ assert .Contains (t , err .Error (), tt .errorMsg )
112+ } else {
113+ // For allowed registries, should NOT be "unsupported registry" error
114+ assert .NotContains (t , err .Error (), "unsupported OCI registry" )
111115 }
112116 } else {
113117 assert .NoError (t , err )
@@ -116,39 +120,6 @@ func TestValidateOCI_RealPackages(t *testing.T) {
116120 }
117121}
118122
119- func TestValidateOCI_AllRegistriesSupported (t * testing.T ) {
120- ctx := context .Background ()
121-
122- // Test that various registry formats are accepted (they will fail on fetch, not on validation)
123- testRegistries := []string {
124- "docker.io/test/image:latest" ,
125- "ghcr.io/test/image:latest" ,
126- "quay.io/test/image:latest" ,
127- "gcr.io/test/image:latest" ,
128- "public.ecr.aws/test/image:latest" ,
129- "registry.gitlab.com/test/image:latest" ,
130- "custom-registry.com/test/image:latest" ,
131- }
132-
133- for _ , registry := range testRegistries {
134- t .Run (registry , func (t * testing.T ) {
135- pkg := model.Package {
136- RegistryType : model .RegistryTypeOCI ,
137- Identifier : registry ,
138- }
139-
140- err := registries .ValidateOCI (ctx , pkg , "com.example/test" )
141-
142- // Should NOT fail with "unsupported registry" error
143- // Will fail with "not found" or similar, but that means the registry was accepted
144- if err != nil {
145- assert .NotContains (t , err .Error (), "unsupported registry" )
146- assert .NotContains (t , err .Error (), "registry type and base URL do not match" )
147- }
148- })
149- }
150- }
151-
152123func TestValidateOCI_RejectsOldFormat (t * testing.T ) {
153124 ctx := context .Background ()
154125
@@ -184,29 +155,14 @@ func TestValidateOCI_RejectsOldFormat(t *testing.T) {
184155 },
185156 errorMessage : "OCI packages must not have 'fileSha256' field" ,
186157 },
187- {
188- name : "OCI package with canonical format should pass format validation" ,
189- pkg : model.Package {
190- RegistryType : model .RegistryTypeOCI ,
191- Identifier : "docker.io/test/image:latest" ,
192- },
193- errorMessage : "" , // Should pass old format check (will fail later due to image not existing)
194- },
195158 }
196159
197160 for _ , tt := range tests {
198161 t .Run (tt .name , func (t * testing.T ) {
199162 err := registries .ValidateOCI (ctx , tt .pkg , "com.example/test" )
200163
201- if tt .errorMessage != "" {
202- assert .Error (t , err )
203- assert .Contains (t , err .Error (), tt .errorMessage )
204- } else if err != nil {
205- // Should not fail with old format error (may fail with other errors like image not found)
206- assert .NotContains (t , err .Error (), "must not have 'registryBaseUrl'" )
207- assert .NotContains (t , err .Error (), "must not have 'version'" )
208- assert .NotContains (t , err .Error (), "must not have 'fileSha256'" )
209- }
164+ assert .Error (t , err )
165+ assert .Contains (t , err .Error (), tt .errorMessage )
210166 })
211167 }
212168}
@@ -241,3 +197,16 @@ func TestValidateOCI_InvalidReferences(t *testing.T) {
241197 })
242198 }
243199}
200+
201+ func TestValidateOCI_EmptyIdentifier (t * testing.T ) {
202+ ctx := context .Background ()
203+
204+ pkg := model.Package {
205+ RegistryType : model .RegistryTypeOCI ,
206+ Identifier : "" ,
207+ }
208+
209+ err := registries .ValidateOCI (ctx , pkg , "com.example/test" )
210+ assert .Error (t , err )
211+ assert .Contains (t , err .Error (), "package identifier is required" )
212+ }
0 commit comments