Skip to content

Commit 0c0c901

Browse files
committed
fix: add required key checks for coder resources
1 parent 3ac0c62 commit 0c0c901

File tree

1 file changed

+45
-11
lines changed

1 file changed

+45
-11
lines changed

cmd/readmevalidation/coderresources.go

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
var (
1919
supportedResourceTypes = []string{"modules", "templates"}
20+
operatingSystems = []string{"windows", "macos", "linux"}
2021

2122
// TODO: This is a holdover from the validation logic used by the Coder Modules repo. It gives us some assurance, but
2223
// realistically, we probably want to parse any Terraform code snippets, and make some deeper guarantees about how it's
@@ -25,11 +26,21 @@ var (
2526
)
2627

2728
type coderResourceFrontmatter struct {
28-
Description string `yaml:"description"`
29-
IconURL string `yaml:"icon"`
30-
DisplayName *string `yaml:"display_name"`
31-
Verified *bool `yaml:"verified"`
32-
Tags []string `yaml:"tags"`
29+
Description string `yaml:"description"`
30+
IconURL string `yaml:"icon"`
31+
DisplayName *string `yaml:"display_name"`
32+
Verified *bool `yaml:"verified"`
33+
Tags []string `yaml:"tags"`
34+
OperatingSystems []string `yaml:"supported_os"`
35+
}
36+
37+
// A slice version of the struct tags from coderResourceFrontmatter. Might be worth using reflection to generate this
38+
// list at runtime in the future, but this should be okay for now
39+
var supportedCoderResourceStructKeys = []string{
40+
"description", "icon", "display_name", "verified", "tags", "supported_os",
41+
// TODO: This is an old, officially deprecated key from an older version of the repo. We can remove this once we
42+
// make sure that the Registry Server is no longer checking this field.
43+
"maintainer_github",
3344
}
3445

3546
// coderResourceReadme represents a README describing a Terraform resource used
@@ -42,6 +53,17 @@ type coderResourceReadme struct {
4253
frontmatter coderResourceFrontmatter
4354
}
4455

56+
func validateSupportedOperatingSystems(systems []string) []error {
57+
var errs []error
58+
for _, s := range systems {
59+
if slices.Contains(operatingSystems, s) {
60+
continue
61+
}
62+
errs = append(errs, xerrors.Errorf("detected unknown operating system %q", s))
63+
}
64+
return errs
65+
}
66+
4567
func validateCoderResourceDisplayName(displayName *string) error {
4668
if displayName != nil && *displayName == "" {
4769
return xerrors.New("if defined, display_name must not be empty string")
@@ -211,19 +233,31 @@ func validateCoderResourceReadme(rm coderResourceReadme) []error {
211233
for _, err := range validateCoderResourceIconURL(rm.frontmatter.IconURL) {
212234
errs = append(errs, addFilePathToError(rm.filePath, err))
213235
}
236+
for _, err := range validateSupportedOperatingSystems(rm.frontmatter.OperatingSystems) {
237+
errs = append(errs, addFilePathToError(rm.filePath, err))
238+
}
214239

215240
return errs
216241
}
217242

218-
func parseCoderResourceReadme(resourceType string, rm readme) (coderResourceReadme, error) {
243+
func parseCoderResourceReadme(resourceType string, rm readme) (coderResourceReadme, []error) {
219244
fm, body, err := separateFrontmatter(rm.rawText)
220245
if err != nil {
221-
return coderResourceReadme{}, xerrors.Errorf("%q: failed to parse frontmatter: %v", rm.filePath, err)
246+
return coderResourceReadme{}, []error{xerrors.Errorf("%q: failed to parse frontmatter: %v", rm.filePath, err)}
247+
}
248+
249+
keyErrs := validateFrontmatterYamlKeys(fm, supportedCoderResourceStructKeys)
250+
if len(keyErrs) != 0 {
251+
remapped := []error{}
252+
for _, e := range keyErrs {
253+
remapped = append(remapped, addFilePathToError(rm.filePath, e))
254+
}
255+
return coderResourceReadme{}, remapped
222256
}
223257

224258
yml := coderResourceFrontmatter{}
225259
if err := yaml.Unmarshal([]byte(fm), &yml); err != nil {
226-
return coderResourceReadme{}, xerrors.Errorf("%q: failed to parse: %v", rm.filePath, err)
260+
return coderResourceReadme{}, []error{xerrors.Errorf("%q: failed to parse: %v", rm.filePath, err)}
227261
}
228262

229263
return coderResourceReadme{
@@ -238,9 +272,9 @@ func parseCoderResourceReadmeFiles(resourceType string, rms []readme) (map[strin
238272
resources := map[string]coderResourceReadme{}
239273
var yamlParsingErrs []error
240274
for _, rm := range rms {
241-
p, err := parseCoderResourceReadme(resourceType, rm)
242-
if err != nil {
243-
yamlParsingErrs = append(yamlParsingErrs, err)
275+
p, errs := parseCoderResourceReadme(resourceType, rm)
276+
if len(errs) != 0 {
277+
yamlParsingErrs = append(yamlParsingErrs, errs...)
244278
continue
245279
}
246280

0 commit comments

Comments
 (0)