Visitar URL original
fix(validators): reject incomplete repository metadata · modelcontextprotocol/registry@be0c973 · GitHub
Skip to content

Commit be0c973

Browse files
committed
fix(validators): reject incomplete repository metadata
1 parent a25f166 commit be0c973

3 files changed

Lines changed: 92 additions & 2 deletions

File tree

‎internal/api/handlers/v0/publish_test.go‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,25 @@ func TestPublishEndpoint(t *testing.T) {
102102
},
103103
expectedStatus: http.StatusOK,
104104
},
105+
{
106+
name: "reject publish with empty repository",
107+
requestBody: apiv0.ServerJSON{
108+
Schema: model.CurrentSchemaURL,
109+
Name: "example/test-server",
110+
Description: "A test server",
111+
Repository: &model.Repository{},
112+
Version: "1.0.0",
113+
},
114+
tokenClaims: &auth.JWTClaims{
115+
AuthMethod: auth.MethodNone,
116+
Permissions: []auth.Permission{
117+
{Action: auth.PermissionActionPublish, ResourcePattern: "example/*"},
118+
},
119+
},
120+
setupRegistryService: func(_ service.RegistryService) {},
121+
expectedStatus: http.StatusUnprocessableEntity,
122+
expectedError: "Failed to publish server, invalid schema: call /validate for details",
123+
},
105124
{
106125
name: "missing authorization header",
107126
requestBody: apiv0.ServerJSON{},

‎internal/validators/validators.go‎

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,32 @@ func ValidateServerJSON(serverJSON *apiv0.ServerJSON, opts ValidationOptions) *V
119119
func validateRepository(ctx *ValidationContext, obj *model.Repository) *ValidationResult {
120120
result := &ValidationResult{Valid: true, Issues: []ValidationIssue{}}
121121

122-
// Skip validation if repository is nil or empty (optional field)
123-
if obj == nil || (obj.URL == "" && obj.Source == "") {
122+
// The repository field is optional, but its required fields must be present
123+
// when the repository object itself is provided.
124+
if obj == nil {
125+
return result
126+
}
127+
if obj.URL == "" {
128+
issue := NewValidationIssue(
129+
ValidationIssueTypeSemantic,
130+
ctx.Field("url").String(),
131+
"repository url is required when repository is provided",
132+
ValidationIssueSeverityError,
133+
"repository-url-required",
134+
)
135+
result.AddIssue(issue)
136+
}
137+
if obj.Source == "" {
138+
issue := NewValidationIssue(
139+
ValidationIssueTypeSemantic,
140+
ctx.Field("source").String(),
141+
"repository source is required when repository is provided",
142+
ValidationIssueSeverityError,
143+
"repository-source-required",
144+
)
145+
result.AddIssue(issue)
146+
}
147+
if !result.Valid {
124148
return result
125149
}
126150

‎internal/validators/validators_test.go‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,16 @@ func TestValidate(t *testing.T) {
249249
},
250250
expectedError: validators.ErrMultipleSlashesInServerName.Error(),
251251
},
252+
{
253+
name: "server without repository",
254+
serverDetail: apiv0.ServerJSON{
255+
Schema: model.CurrentSchemaURL,
256+
Name: "com.example/test-server",
257+
Description: "A test server",
258+
Version: "1.0.0",
259+
},
260+
expectedError: "",
261+
},
252262
{
253263
name: "valid server detail with all fields",
254264
serverDetail: apiv0.ServerJSON{
@@ -281,6 +291,43 @@ func TestValidate(t *testing.T) {
281291
},
282292
expectedError: "",
283293
},
294+
{
295+
name: "server with empty repository",
296+
serverDetail: apiv0.ServerJSON{
297+
Schema: model.CurrentSchemaURL,
298+
Name: "com.example/test-server",
299+
Description: "A test server",
300+
Repository: &model.Repository{},
301+
Version: "1.0.0",
302+
},
303+
expectedError: "repository url is required when repository is provided",
304+
},
305+
{
306+
name: "server with repository missing URL",
307+
serverDetail: apiv0.ServerJSON{
308+
Schema: model.CurrentSchemaURL,
309+
Name: "com.example/test-server",
310+
Description: "A test server",
311+
Repository: &model.Repository{
312+
Source: "github",
313+
},
314+
Version: "1.0.0",
315+
},
316+
expectedError: "repository url is required when repository is provided",
317+
},
318+
{
319+
name: "server with repository missing source",
320+
serverDetail: apiv0.ServerJSON{
321+
Schema: model.CurrentSchemaURL,
322+
Name: "com.example/test-server",
323+
Description: "A test server",
324+
Repository: &model.Repository{
325+
URL: "https://github.com/owner/repo",
326+
},
327+
Version: "1.0.0",
328+
},
329+
expectedError: "repository source is required when repository is provided",
330+
},
284331
{
285332
name: "server with invalid repository source",
286333
serverDetail: apiv0.ServerJSON{

0 commit comments

Comments
 (0)