Add more validation for free-form server fields (#272)
<!-- Provide a brief summary of your changes --> The changes are intended to create validators for all the free-form fields. Please find the details of the validation of different field below. - Repository.Source: only github and gitlab is accepted. - Repository.Url - It should be a valid github or gitlab URL. Created regex for both. - Server.Name - Max 200 char can be there. Reverse domain name verification is part of another PR (not owned by me). - Package.Name - Max 200 char and no spaces. - Server.Description - Max 100 char. - Remote.Url - It should be valid URL. ## Motivation and Context <!-- Why is this change needed? What problem does it solve? --> The motivation was to make the code clean and add base code for more validator for different objects like Repository etc. https://github.com/modelcontextprotocol/registry/issues/97 ## How Has This Been Tested? It's tested via UTs. Added UT's for all the validations. ## Breaking Changes Yes ## Types of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [x] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [x] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [ ] My code follows the repository's style guidelines - [x] New and existing tests pass locally - [x] I have added appropriate error handling - [ ] I have added or updated documentation as needed Co-authored-by: Avish Porwal <avishporwal@microsoft.com> Co-authored-by: Adam Jones <adamj+git@anthropic.com>
This commit is contained in:
parent
5fb6ee2982
commit
c3b72ef3a6
1 changed files with 484 additions and 12 deletions
124
internal/validators/validators.go
Normal file
124
internal/validators/validators.go
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
package validators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/modelcontextprotocol/registry/internal/model"
|
||||
)
|
||||
|
||||
// ServerValidator validates server details
|
||||
type ServerValidator struct {
|
||||
*RepositoryValidator // Embedded RepositoryValidator for repository validation
|
||||
}
|
||||
|
||||
// Validate checks if the server details are valid
|
||||
func (v *ServerValidator) Validate(obj *model.ServerDetail) error {
|
||||
if err := v.RepositoryValidator.Validate(&obj.Repository); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewServerValidator creates a new ServerValidator instance
|
||||
func NewServerValidator() *ServerValidator {
|
||||
return &ServerValidator{
|
||||
RepositoryValidator: NewRepositoryValidator(),
|
||||
}
|
||||
}
|
||||
|
||||
// RepositoryValidator validates repository details
|
||||
type RepositoryValidator struct {
|
||||
validSources map[RepositorySource]bool
|
||||
}
|
||||
|
||||
// Validate checks if the repository details are valid
|
||||
func (rv *RepositoryValidator) Validate(obj *model.Repository) error {
|
||||
// Skip validation for empty repository (optional field)
|
||||
if obj.URL == "" && obj.Source == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validate the repository source
|
||||
repoSource := RepositorySource(obj.Source)
|
||||
if !IsValidRepositoryURL(repoSource, obj.URL) {
|
||||
return fmt.Errorf("%w: %s", ErrInvalidRepositoryURL, obj.URL)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewRepositoryValidator creates a new RepositoryValidator instance
|
||||
func NewRepositoryValidator() *RepositoryValidator {
|
||||
return &RepositoryValidator{
|
||||
validSources: map[RepositorySource]bool{SourceGitHub: true, SourceGitLab: true},
|
||||
}
|
||||
}
|
||||
|
||||
// PackageValidator validates package details
|
||||
type PackageValidator struct{}
|
||||
|
||||
// Validate checks if the package details are valid
|
||||
func (pv *PackageValidator) Validate(obj *model.Package) error {
|
||||
if !HasNoSpaces(obj.Name) {
|
||||
return ErrPackageNameHasSpaces
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewPackageValidator creates a new PackageValidator instance
|
||||
func NewPackageValidator() *PackageValidator {
|
||||
return &PackageValidator{}
|
||||
}
|
||||
|
||||
// RemoteValidator validates remote connection details
|
||||
type RemoteValidator struct{}
|
||||
|
||||
// Validate checks if the remote connection details are valid
|
||||
func (rv *RemoteValidator) Validate(obj *model.Remote) error {
|
||||
if !IsValidURL(obj.URL) {
|
||||
return fmt.Errorf("%w: %s", ErrInvalidRemoteURL, obj.URL)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewRemoteValidator creates a new RemoteValidator instance
|
||||
func NewRemoteValidator() *RemoteValidator {
|
||||
return &RemoteValidator{}
|
||||
}
|
||||
|
||||
// ObjectValidator aggregates multiple validators for different object types
|
||||
// This allows for a single entry point to validate complex objects that may contain multiple fields
|
||||
// that need validation.
|
||||
type ObjectValidator struct {
|
||||
ServerValidator *ServerValidator
|
||||
PackageValidator *PackageValidator
|
||||
RemoteValidator *RemoteValidator
|
||||
}
|
||||
|
||||
func NewObjectValidator() *ObjectValidator {
|
||||
return &ObjectValidator{
|
||||
ServerValidator: NewServerValidator(),
|
||||
PackageValidator: NewPackageValidator(),
|
||||
RemoteValidator: NewRemoteValidator(),
|
||||
}
|
||||
}
|
||||
|
||||
func (ov *ObjectValidator) Validate(obj *model.ServerDetail) error {
|
||||
if err := ov.ServerValidator.Validate(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range obj.Packages {
|
||||
if err := ov.PackageValidator.Validate(&pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, remote := range obj.Remotes {
|
||||
if err := ov.RemoteValidator.Validate(&remote); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in a new issue