Skip to content

Commit dbaea55

Browse files
committed
Add validation to reject extra fields in MCPB packages
Signed-off-by: Radoslav Dimitrov <[email protected]>
1 parent 5d0a589 commit dbaea55

File tree

2 files changed

+76
-11
lines changed

2 files changed

+76
-11
lines changed

internal/validators/registries/mcpb.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,20 @@ func ValidateMCPB(ctx context.Context, pkg model.Package, _ string) error {
2727
return ErrMissingIdentifierForMCPB
2828
}
2929

30-
err := validateMCPBUrl(pkg.Identifier)
31-
if err != nil {
32-
return err
30+
// Validate that old format fields are not present
31+
// MCPB packages use URL in identifier, version is embedded in the URL
32+
if pkg.Version != "" {
33+
return fmt.Errorf("MCPB packages must not have 'version' field - version should be embedded in the download URL")
34+
}
35+
if pkg.RegistryBaseURL != "" {
36+
return fmt.Errorf("MCPB packages must not have 'registryBaseUrl' field - use the full download URL in 'identifier' instead")
3337
}
3438

35-
inferredBaseURL, err := inferMCPBRegistryBaseURL(pkg.Identifier)
39+
err := validateMCPBUrl(pkg.Identifier)
3640
if err != nil {
3741
return err
3842
}
3943

40-
if pkg.RegistryBaseURL == "" {
41-
pkg.RegistryBaseURL = inferredBaseURL
42-
} else if pkg.RegistryBaseURL != inferredBaseURL {
43-
return fmt.Errorf("MCPB package '%s' has inconsistent registry base URL: %s (expected: %s)",
44-
pkg.Identifier, pkg.RegistryBaseURL, inferredBaseURL)
45-
}
46-
4744
// Parse the URL to validate format
4845
url, err := url.Parse(pkg.Identifier)
4946
if err != nil {

internal/validators/registries/mcpb_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,71 @@ func TestValidateMCPB(t *testing.T) {
119119
})
120120
}
121121
}
122+
123+
func TestValidateMCPB_RejectsExtraFields(t *testing.T) {
124+
ctx := context.Background()
125+
126+
tests := []struct {
127+
name string
128+
pkg model.Package
129+
errorMessage string
130+
}{
131+
{
132+
name: "MCPB package with version field should be rejected",
133+
pkg: model.Package{
134+
RegistryType: model.RegistryTypeMCPB,
135+
Identifier: "https://github.com/example/repo/releases/download/v1.0.0/server.mcpb",
136+
Version: "1.0.0",
137+
FileSHA256: "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce",
138+
},
139+
errorMessage: "MCPB packages must not have 'version' field",
140+
},
141+
{
142+
name: "MCPB package with registryBaseUrl should be rejected",
143+
pkg: model.Package{
144+
RegistryType: model.RegistryTypeMCPB,
145+
Identifier: "https://github.com/example/repo/releases/download/v1.0.0/server.mcpb",
146+
RegistryBaseURL: "https://github.com",
147+
FileSHA256: "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce",
148+
},
149+
errorMessage: "MCPB packages must not have 'registryBaseUrl' field",
150+
},
151+
{
152+
name: "MCPB package with both extra fields should fail on version first",
153+
pkg: model.Package{
154+
RegistryType: model.RegistryTypeMCPB,
155+
Identifier: "https://github.com/example/repo/releases/download/v1.0.0/server.mcpb",
156+
Version: "1.0.0",
157+
RegistryBaseURL: "https://github.com",
158+
FileSHA256: "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce",
159+
},
160+
errorMessage: "MCPB packages must not have 'version' field",
161+
},
162+
{
163+
name: "MCPB package with canonical format should pass extra field validation",
164+
pkg: model.Package{
165+
RegistryType: model.RegistryTypeMCPB,
166+
Identifier: "https://github.com/domdomegg/airtable-mcp-server/releases/download/v1.7.2/airtable-mcp-server.mcpb",
167+
FileSHA256: "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce",
168+
},
169+
errorMessage: "", // Should pass extra field check (will succeed as this is a real package)
170+
},
171+
}
172+
173+
for _, tt := range tests {
174+
t.Run(tt.name, func(t *testing.T) {
175+
err := registries.ValidateMCPB(ctx, tt.pkg, "com.example/test")
176+
177+
if tt.errorMessage != "" {
178+
assert.Error(t, err)
179+
assert.Contains(t, err.Error(), tt.errorMessage)
180+
} else {
181+
// Should not fail with extra field error (may pass completely for real package)
182+
if err != nil {
183+
assert.NotContains(t, err.Error(), "must not have 'version'")
184+
assert.NotContains(t, err.Error(), "must not have 'registryBaseUrl'")
185+
}
186+
}
187+
})
188+
}
189+
}

0 commit comments

Comments
 (0)