@@ -2,8 +2,8 @@ package main
22
33import (
44 "bufio"
5+ "context"
56 "errors"
6- "log"
77 "net/url"
88 "os"
99 "path"
@@ -15,7 +15,14 @@ import (
1515 "gopkg.in/yaml.v3"
1616)
1717
18- var supportedResourceTypes = []string {"modules" , "templates" }
18+ var (
19+ supportedResourceTypes = []string {"modules" , "templates" }
20+
21+ // TODO: This is a holdover from the validation logic used by the Coder Modules repo. It gives us some assurance, but
22+ // realistically, we probably want to parse any Terraform code snippets, and make some deeper guarantees about how it's
23+ // structured. Just validating whether it *can* be parsed as Terraform would be a big improvement.
24+ terraformVersionRe = regexp .MustCompile (`^\s*\bversion\s+=` )
25+ )
1926
2027type coderResourceFrontmatter struct {
2128 Description string `yaml:"description"`
@@ -49,36 +56,36 @@ func validateCoderResourceDescription(description string) error {
4956 return nil
5057}
5158
52- func validateCoderResourceIconURL (iconURL string ) []error {
53- problems := []error {}
59+ func isPermittedRelativeURL (checkURL string ) bool {
60+ // Would normally be skittish about having relative paths like this, but it should be safe because we have
61+ // guarantees about the structure of the repo, and where this logic will run.
62+ return strings .HasPrefix (checkURL , "./" ) || strings .HasPrefix (checkURL , "/" ) || strings .HasPrefix (checkURL , "../../../../.icons" )
63+ }
5464
65+ func validateCoderResourceIconURL (iconURL string ) []error {
5566 if iconURL == "" {
56- problems = append (problems , xerrors .New ("icon URL cannot be empty" ))
57- return problems
67+ return []error {xerrors .New ("icon URL cannot be empty" )}
5868 }
5969
60- isAbsoluteURL := ! strings .HasPrefix (iconURL , "." ) && ! strings .HasPrefix (iconURL , "/" )
61- if isAbsoluteURL {
70+ errs := []error {}
71+
72+ // If the URL does not have a relative path.
73+ if ! strings .HasPrefix (iconURL , "." ) && ! strings .HasPrefix (iconURL , "/" ) {
6274 if _ , err := url .ParseRequestURI (iconURL ); err != nil {
63- problems = append (problems , xerrors .New ("absolute icon URL is not correctly formatted" ))
75+ errs = append (errs , xerrors .New ("absolute icon URL is not correctly formatted" ))
6476 }
6577 if strings .Contains (iconURL , "?" ) {
66- problems = append (problems , xerrors .New ("icon URLs cannot contain query parameters" ))
78+ errs = append (errs , xerrors .New ("icon URLs cannot contain query parameters" ))
6779 }
68- return problems
80+ return errs
6981 }
7082
71- // Would normally be skittish about having relative paths like this, but it
72- // should be safe because we have guarantees about the structure of the
73- // repo, and where this logic will run.
74- isPermittedRelativeURL := strings .HasPrefix (iconURL , "./" ) ||
75- strings .HasPrefix (iconURL , "/" ) ||
76- strings .HasPrefix (iconURL , "../../../../.icons" )
77- if ! isPermittedRelativeURL {
78- problems = append (problems , xerrors .Errorf ("relative icon URL %q must either be scoped to that module's directory, or the top-level /.icons directory (this can usually be done by starting the path with \" ../../../.icons\" )" , iconURL ))
83+ // If the URL has a relative path.
84+ if ! isPermittedRelativeURL (iconURL ) {
85+ errs = append (errs , xerrors .Errorf ("relative icon URL %q must either be scoped to that module's directory, or the top-level /.icons directory (this can usually be done by starting the path with \" ../../../.icons\" )" , iconURL ))
7986 }
8087
81- return problems
88+ return errs
8289}
8390
8491func validateCoderResourceTags (tags []string ) error {
@@ -89,9 +96,8 @@ func validateCoderResourceTags(tags []string) error {
8996 return nil
9097 }
9198
92- // All of these tags are used for the module/template filter controls in the
93- // Registry site. Need to make sure they can all be placed in the browser
94- // URL without issue.
99+ // All of these tags are used for the module/template filter controls in the Registry site. Need to make sure they
100+ // can all be placed in the browser URL without issue.
95101 invalidTags := []string {}
96102 for _ , t := range tags {
97103 if t != url .QueryEscape (t ) {
@@ -105,16 +111,11 @@ func validateCoderResourceTags(tags []string) error {
105111 return nil
106112}
107113
108- // Todo: This is a holdover from the validation logic used by the Coder Modules
109- // repo. It gives us some assurance, but realistically, we probably want to
110- // parse any Terraform code snippets, and make some deeper guarantees about how
111- // it's structured. Just validating whether it *can* be parsed as Terraform
112- // would be a big improvement.
113- var terraformVersionRe = regexp .MustCompile (`^\s*\bversion\s+=` )
114-
115114func validateCoderResourceReadmeBody (body string ) []error {
116- trimmed := strings .TrimSpace (body )
117115 var errs []error
116+
117+ trimmed := strings .TrimSpace (body )
118+ // TODO: this may cause unexpected behavior since the errors slice may have a 0 length. Add a test.
118119 errs = append (errs , validateReadmeBody (trimmed )... )
119120
120121 foundParagraph := false
@@ -130,9 +131,8 @@ func validateCoderResourceReadmeBody(body string) []error {
130131 lineNum ++
131132 nextLine := lineScanner .Text ()
132133
133- // Code assumes that invalid headers would've already been handled by
134- // the base validation function, so we don't need to check deeper if the
135- // first line isn't an h1.
134+ // Code assumes that invalid headers would've already been handled by the base validation function, so we don't
135+ // need to check deeper if the first line isn't an h1.
136136 if lineNum == 1 {
137137 if ! strings .HasPrefix (nextLine , "# " ) {
138138 break
@@ -159,15 +159,13 @@ func validateCoderResourceReadmeBody(body string) []error {
159159 continue
160160 }
161161
162- // Code assumes that we can treat this case as the end of the "h1
163- // section" and don't need to process any further lines.
162+ // Code assumes that we can treat this case as the end of the "h1 section" and don't need to process any further lines.
164163 if lineNum > 1 && strings .HasPrefix (nextLine , "#" ) {
165164 break
166165 }
167166
168- // Code assumes that if we've reached this point, the only other options
169- // are: (1) empty spaces, (2) paragraphs, (3) HTML, and (4) asset
170- // references made via [] syntax.
167+ // Code assumes that if we've reached this point, the only other options are:
168+ // (1) empty spaces, (2) paragraphs, (3) HTML, and (4) asset references made via [] syntax.
171169 trimmedLine := strings .TrimSpace (nextLine )
172170 isParagraph := trimmedLine != "" && ! strings .HasPrefix (trimmedLine , "![" ) && ! strings .HasPrefix (trimmedLine , "<" )
173171 foundParagraph = foundParagraph || isParagraph
@@ -250,7 +248,7 @@ func parseCoderResourceReadmeFiles(resourceType string, rms []readme) (map[strin
250248 }
251249 if len (yamlParsingErrs ) != 0 {
252250 return nil , validationPhaseError {
253- phase : validationPhaseReadmeParsing ,
251+ phase : validationPhaseReadme ,
254252 errors : yamlParsingErrs ,
255253 }
256254 }
@@ -264,7 +262,7 @@ func parseCoderResourceReadmeFiles(resourceType string, rms []readme) (map[strin
264262 }
265263 if len (yamlValidationErrors ) != 0 {
266264 return nil , validationPhaseError {
267- phase : validationPhaseReadmeParsing ,
265+ phase : validationPhaseReadme ,
268266 errors : yamlValidationErrors ,
269267 }
270268 }
@@ -274,7 +272,7 @@ func parseCoderResourceReadmeFiles(resourceType string, rms []readme) (map[strin
274272
275273// Todo: Need to beef up this function by grabbing each image/video URL from
276274// the body's AST.
277- func validateCoderResourceRelativeUrls (_ map [string ]coderResourceReadme ) error {
275+ func validateCoderResourceRelativeURLs (_ map [string ]coderResourceReadme ) error {
278276 return nil
279277}
280278
@@ -321,7 +319,7 @@ func aggregateCoderResourceReadmeFiles(resourceType string) ([]readme, error) {
321319
322320 if len (errs ) != 0 {
323321 return nil , validationPhaseError {
324- phase : validationPhaseFileLoad ,
322+ phase : validationPhaseFile ,
325323 errors : errs ,
326324 }
327325 }
@@ -338,17 +336,16 @@ func validateAllCoderResourceFilesOfType(resourceType string) error {
338336 return err
339337 }
340338
341- log . Printf ( "Processing %d README files\n " , len (allReadmeFiles ))
339+ logger . Info ( context . Background (), "rocessing README files" , "num_files " , len (allReadmeFiles ))
342340 resources , err := parseCoderResourceReadmeFiles (resourceType , allReadmeFiles )
343341 if err != nil {
344342 return err
345343 }
346- log . Printf ( "Processed %d README files as valid Coder resources with type %q" , len (resources ), resourceType )
344+ logger . Info ( context . Background (), "rocessed README files as valid Coder resources" , "num_files" , len (resources ), "type" , resourceType )
347345
348- err = validateCoderResourceRelativeUrls (resources )
349- if err != nil {
346+ if err := validateCoderResourceRelativeURLs (resources ); err != nil {
350347 return err
351348 }
352- log . Printf ( "All relative URLs for %s READMEs are valid\n " , resourceType )
349+ logger . Info ( context . Background (), "all relative URLs for READMEs are valid" , "type " , resourceType )
353350 return nil
354351}
0 commit comments