wip: commit progress for module validation

This commit is contained in:
Michael Smith 2025-04-15 16:35:33 +00:00
parent 18680d0a15
commit 17c9667db6
3 changed files with 105 additions and 3 deletions

View File

@ -0,0 +1,100 @@
package main
import (
"errors"
"fmt"
"net/url"
"strings"
)
type coderResourceFrontmatter struct {
Description string `yaml:"description"`
IconURL string `yaml:"icon"`
DisplayName *string `yaml:"display_name"`
Tags []string `yaml:"tags"`
Verified *bool `yaml:"verified"`
}
type coderResourceReadme struct {
oldFrontmatter *coderResourceFrontmatter
newFrontmatter *coderResourceFrontmatter
newBody string
moduleName string
filePath string
}
func validateCoderResourceDisplayName(displayName *string) error {
if displayName == nil {
return nil
}
if *displayName == "" {
return errors.New("if defined, display_name must not be empty string")
}
return nil
}
func validateCoderResourceDescription(description string) error {
if description == "" {
return errors.New("frontmatter description cannot be empty")
}
return nil
}
func validateCoderResourceIconURL(iconURL string) []error {
problems := []error{}
if iconURL == "" {
problems = append(problems, errors.New("icon URL cannot be empty"))
return problems
}
isAbsoluteURL := !strings.HasPrefix(iconURL, ".") && !strings.HasPrefix(iconURL, "/")
if isAbsoluteURL {
if _, err := url.ParseRequestURI(iconURL); err != nil {
problems = append(problems, errors.New("absolute icon URL is not correctly formatted"))
}
if strings.Contains(iconURL, "?") {
problems = append(problems, errors.New("icon URLs cannot contain query parameters"))
}
return problems
}
// Would normally be skittish about having relative paths like this, but it
// should be safe because we have guarantees about the structure of the
// repo, and where this logic will run
isPermittedRelativeURL := strings.HasPrefix(iconURL, "./") ||
strings.HasPrefix(iconURL, "/") ||
strings.HasPrefix(iconURL, "../../../.logos")
if !isPermittedRelativeURL {
problems = append(problems, errors.New("relative icon URL must either be scoped to that module's directory, or the top-level /.logos directory"))
}
return problems
}
func validateCoderResourceTags(tags []string) error {
if len(tags) == 0 {
return nil
}
// All of these tags are used for the module/template filter controls in the
// Registry site. Need to make sure they can all be placed in the browser
// URL without issue
invalidTags := []string{}
for _, t := range tags {
if t != url.QueryEscape(t) {
invalidTags = append(invalidTags, t)
}
}
if len(invalidTags) != 0 {
return fmt.Errorf("found invalid tags (tags that cannot be used for filter state in the Registry website): [%s]", strings.Join(invalidTags, ", "))
}
return nil
}
func validateCoderResourceReadmeBody(body string) []error {
return nil
}

View File

@ -71,10 +71,12 @@ func separateFrontmatter(readmeText string) (string, string, error) {
type validationPhase int
const (
//
validationPhaseStructureValidation validationPhase = iota
// validationPhaseFileStructureValidation indicates when the entire Registry
// directory is being verified for having all files be placed in the file
// system as expected.
validationPhaseFileStructureValidation validationPhase = iota
// validationPhaseFileLoad indicates when a README file is being read from
// validationPhaseFileLoad indicates when README files are being read from
// the file system
validationPhaseFileLoad