Skip to content

Commit 41aacc1

Browse files
authored
Ban 'latest' as a reserved version string (#413)
## Summary - Adds validation to prevent servers from being published with version string "latest" - "latest" is now a reserved keyword that cannot be used as a version string ## Implementation - Added `ErrReservedVersionString` error constant - Created `validateVersion` function to check for reserved version strings - Integrated validation into the package field validation flow - Added comprehensive test coverage --- This is so we can potentially support things like #333 in future more easily, as I imagine we might want to.
1 parent 64b7fc6 commit 41aacc1

File tree

3 files changed

+45
-5
lines changed

3 files changed

+45
-5
lines changed

internal/validators/constants.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var (
1010

1111
// Package validation errors
1212
ErrPackageNameHasSpaces = errors.New("package name cannot contain spaces")
13+
ErrReservedVersionString = errors.New("version string 'latest' is reserved and cannot be used")
1314

1415
// Remote validation errors
1516
ErrInvalidRemoteURL = errors.New("invalid remote URL")

internal/validators/validators.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ func validatePackageField(obj *model.Package) error {
7272
return ErrPackageNameHasSpaces
7373
}
7474

75+
// Validate version string
76+
if err := validateVersion(obj.Version); err != nil {
77+
return err
78+
}
79+
7580
// Validate runtime arguments
7681
for _, arg := range obj.RuntimeArguments {
7782
if err := validateArgument(&arg); err != nil {
@@ -95,6 +100,16 @@ func validatePackageField(obj *model.Package) error {
95100
return nil
96101
}
97102

103+
// validateVersion validates the version string
104+
// NB: we decided that we would not enforce strict semver for version strings
105+
func validateVersion(version string) error {
106+
if version == "latest" {
107+
return ErrReservedVersionString
108+
}
109+
110+
return nil
111+
}
112+
98113
// validateArgument validates argument details
99114
func validateArgument(obj *model.Argument) error {
100115
if obj.Type == model.ArgumentTypeNamed {
@@ -144,12 +159,12 @@ func validateArgumentValueFields(name, value, defaultValue string) error {
144159
// collectAvailableVariables collects all available template variables from a package
145160
func collectAvailableVariables(pkg *model.Package) []string {
146161
var variables []string
147-
162+
148163
// Add environment variable names
149164
for _, env := range pkg.EnvironmentVariables {
150165
variables = append(variables, env.Name)
151166
}
152-
167+
153168
// Add runtime argument names and value hints
154169
for _, arg := range pkg.RuntimeArguments {
155170
if arg.Name != "" {
@@ -159,7 +174,7 @@ func collectAvailableVariables(pkg *model.Package) []string {
159174
variables = append(variables, arg.ValueHint)
160175
}
161176
}
162-
177+
163178
// Add package argument names and value hints
164179
for _, arg := range pkg.PackageArguments {
165180
if arg.Name != "" {
@@ -169,7 +184,7 @@ func collectAvailableVariables(pkg *model.Package) []string {
169184
variables = append(variables, arg.ValueHint)
170185
}
171186
}
172-
187+
173188
return variables
174189
}
175190

@@ -193,7 +208,7 @@ func validatePackageTransport(transport *model.Transport, availableVariables []s
193208
// Check if it's a template variable issue or basic URL issue
194209
templateVars := extractTemplateVariables(transport.URL)
195210
if len(templateVars) > 0 {
196-
return fmt.Errorf("%w: template variables in URL %s reference undefined variables. Available variables: %v",
211+
return fmt.Errorf("%w: template variables in URL %s reference undefined variables. Available variables: %v",
197212
ErrInvalidRemoteURL, transport.URL, availableVariables)
198213
}
199214
return fmt.Errorf("%w: %s", ErrInvalidRemoteURL, transport.URL)

internal/validators/validators_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,30 @@ func TestValidate(t *testing.T) {
193193
},
194194
expectedError: validators.ErrPackageNameHasSpaces.Error(),
195195
},
196+
{
197+
name: "package with reserved version 'latest'",
198+
serverDetail: apiv0.ServerJSON{
199+
Name: "com.example/test-server",
200+
Description: "A test server",
201+
Repository: model.Repository{
202+
URL: "https://github.com/owner/repo",
203+
Source: "github",
204+
},
205+
Version: "1.0.0",
206+
Packages: []model.Package{
207+
{
208+
Identifier: "test-package",
209+
RegistryType: "npm",
210+
RegistryBaseURL: "https://registry.npmjs.org",
211+
Version: "latest",
212+
Transport: model.Transport{
213+
Type: "stdio",
214+
},
215+
},
216+
},
217+
},
218+
expectedError: validators.ErrReservedVersionString.Error(),
219+
},
196220
{
197221
name: "multiple packages with one invalid",
198222
serverDetail: apiv0.ServerJSON{

0 commit comments

Comments
 (0)