"errors"
"fmt"
"reflect"
+ "regexp"
"strconv"
"strings"
)
+const systemKeyPattern = `^arv:[a-zA-Z]`
+
type Vocabulary struct {
reservedTagKeys map[string]bool `json:"-"`
StrictTags bool `json:"strict_tags"`
Values map[string]VocabularyTagValue `json:"values"`
}
-// Cannot have a constant map in Go, so we have to use a function
+// Cannot have a constant map in Go, so we have to use a function.
+// If you are adding a new system property, it SHOULD match `systemKeyPattern`
+// above, and Check will allow it. This map is for historical exceptions that
+// predate standardizing on this prefix.
func (v *Vocabulary) systemTagKeys() map[string]bool {
return map[string]bool{
// Collection keys - set by arvados-cwl-runner
if v == nil {
return nil
}
+ systemKeyRegexp, err := regexp.Compile(systemKeyPattern)
+ if err != nil {
+ return err
+ }
for key, val := range data {
// Checks for key validity
- if v.reservedTagKeys[key] {
+ if systemKeyRegexp.MatchString(key) || v.reservedTagKeys[key] {
// Allow reserved keys to be used even if they are not defined in
// the vocabulary no matter its strictness.
continue
import (
"encoding/json"
+ "fmt"
"regexp"
"strings"
}
}
+func (s *VocabularySuite) TestValidSystemProperties(c *check.C) {
+ s.testVoc.StrictTags = true
+ properties := map[string]interface{}{
+ "arv:gitBranch": "main",
+ "arv:OK": true,
+ "arv:cost": 123,
+ }
+ c.Check(s.testVoc.Check(properties), check.IsNil)
+}
+
+func (s *VocabularySuite) TestSystemPropertiesFirstCharacterAlphabetic(c *check.C) {
+ s.testVoc.StrictTags = true
+ properties := map[string]interface{}{"arv:": "value"}
+ c.Check(s.testVoc.Check(properties), check.NotNil)
+ // If we expand the list of allowed characters in the future, these lists
+ // may need adjustment to match.
+ for _, prefix := range []string{" ", ".", "_", "-", "1"} {
+ for _, suffix := range []string{"", "invalid"} {
+ key := fmt.Sprintf("arv:%s%s", prefix, suffix)
+ properties := map[string]interface{}{key: "value"}
+ c.Check(s.testVoc.Check(properties), check.NotNil)
+ }
+ }
+}
+
+func (s *VocabularySuite) TestSystemPropertiesPrefixTypo(c *check.C) {
+ s.testVoc.StrictTags = true
+ for _, key := range []string{
+ "arv :foo",
+ "arvados",
+ "arvados:foo",
+ "Arv:foo",
+ } {
+ properties := map[string]interface{}{key: "value"}
+ c.Check(s.testVoc.Check(properties), check.NotNil)
+ }
+}
+
func (s *VocabularySuite) TestValidationErrors(c *check.C) {
tests := []struct {
name string