github.com/letsencrypt/boulder@v0.20251208.0/docs/config-validation.md (about) 1 # Configuration Validation 2 3 We use a fork of https://github.com/go-playground/validator which can be found 4 at https://github.com/letsencrypt/validator. 5 6 ## Usage 7 8 By default Boulder validates config files for all components with a registered 9 validator. Validating a config file for a given component is as simple as 10 running the component directly: 11 12 ```shell 13 $ ./bin/boulder-observer -config test/config-next/observer.yml 14 Error validating config file "test/config-next/observer.yml": Key: 'ObsConf.MonConfs[1].Kind' Error:Field validation for 'Kind' failed on the 'oneof' tag 15 ``` 16 17 or by running the `boulder` binary and passing the component name as a 18 subcommand: 19 20 ```shell 21 $ ./bin/boulder boulder-observer -config test/config-next/observer.yml 22 Error validating config file "test/config-next/observer.yml": Key: 'ObsConf.MonConfs[1].Kind' Error:Field validation for 'Kind' failed on the 'oneof' tag 23 ``` 24 25 ## Struct Tag Tips 26 27 You can find the full list of struct tags supported by the validator [here] 28 (https://pkg.go.dev/github.com/go-playground/validator/v10#section-documentation). 29 The following are some tips for struct tags that are commonly used in our 30 configuration files. 31 32 ### `required` 33 34 The required tag means that the field is not allowed to take its zero value, or 35 equivalently, is not allowed to be omitted. Note that this does not validate 36 that slices or maps have contents, it simply guarantees that they are not nil. 37 For fields of those types, you should use min=1 or similar to ensure they are 38 not empty. 39 40 There are also "conditional" required tags, such as `required_with`, 41 `required_with_all`, `required_without`, `required_without_all`, and 42 `required_unless`. These behave exactly like the basic required tag, but only if 43 their conditional (usually the presence or absence of one or more other named 44 fields) is met. 45 46 ### `omitempty` 47 48 The omitempty tag allows a field to be empty, or equivalently, to take its zero 49 value. If the field is omitted, none of the other validation tags on the field 50 will be enforced. This can be useful for tags like validate="omitempty,url", for 51 a field which is optional, but must be a URL if it is present. 52 53 The omitempty tag can be "overruled" by the various conditional required tags. 54 For example, a field with tag `validate="omitempty,url,required_with=Foo"` is 55 allowed to be empty when field Foo is not present, but if field Foo is present, 56 then this field must be present and must be a URL. 57 58 ### `-` 59 60 Normally, config validation descends into all struct-type fields, recursively 61 validating their fields all the way down. Sometimes this can pose a problem, 62 when a nested struct declares one of its fields as required, but a parent struct 63 wants to treat the whole nested struct as optional. The "-" tag tells the 64 validation not to recurse, marking the tagged field as optional, and therefore 65 making all of its sub-fields optional as well. We use this tag for many config 66 duration and password file struct valued fields which are optional in some 67 configs but required in others. 68 69 ### `structonly` 70 71 The structonly tag allows a struct valued field to be empty, or equivalently, to 72 take its zero value, if it's not "overruled" by various conditional tags. If the 73 field is omitted the recursive validation of the structs fields will be skipped. 74 This can be useful for tags like `validate:"required_without=Foo,structonly"` 75 for a struct valued field which is only required, and thus should only be 76 validated, if field `Foo` is not present. 77 78 ### `min=1`, `gte=1` 79 80 These validate that the value of integer valued field is greater than zero and 81 that the length of the slice or map is greater than zero. 82 83 For instance, the following would be valid config for a slice valued field 84 tagged with `required`. 85 ```json 86 { 87 "foo": [], 88 } 89 ``` 90 91 But, only the following would be valid config for a slice valued field tagged 92 with `min=1`. 93 ```json 94 { 95 "foo": ["bar"], 96 } 97 ``` 98 99 ### `len` 100 101 Same as `eq` (equal to) but can also be used to validate the length of the 102 strings. 103 104 ### `hostname_port` 105 106 The 107 [docs](https://pkg.go.dev/github.com/go-playground/validator/v10#hdr-HostPort) 108 for this tag are scant with detail, but it validates that the value is a valid 109 RFC 1123 hostname and port. It is used to validate many of the 110 `ListenAddress` and `DebugAddr` fields of our components. 111 112 #### Future Work 113 114 This tag is compatible with IPv4 addresses, but not IPv6 addresses. We should 115 consider fixing this in our fork of the validator. 116 117 ### `dive` 118 119 This tag is used to validate the values of a slice or map. For instance, the 120 following would be valid config for a slice valued field (`[]string`) tagged 121 with `min=1,dive,oneof=bar baz`. 122 123 ```json 124 { 125 "foo": ["bar", "baz"], 126 } 127 ``` 128 129 Note that the `dive` tag introduces an order-dependence in writing tags: tags 130 that come before `dive` apply to the current field, while tags that come after 131 `dive` apply to the current field's child values. In the example above: `min=1` 132 applies to the length of the slice (`[]string`), while `oneof=bar baz` applies 133 to the value of each string in the slice. 134 135 We can also use `dive` to validate the values of a map. For instance, the 136 following would be valid config for a map valued field (`map[string]string`) 137 tagged with `min=1,dive,oneof=one two`. 138 139 ```json 140 { 141 "foo": { 142 "bar": "one", 143 "baz": "two" 144 }, 145 } 146 ``` 147 148 `dive` can also be invoked multiple times to validate the values of nested 149 slices or maps. For instance, the following would be valid config for a slice of 150 slice valued field (`[][]string`) tagged with `min=1,dive,min=2,dive,oneof=bar 151 baz`. 152 153 ```json 154 { 155 "foo": [ 156 ["bar", "baz"], 157 ["baz", "bar"], 158 ], 159 } 160 ``` 161 162 - `min=1` will be applied to the outer slice (`[]`). 163 - `min=2` will be applied to inner slice (`[]string`). 164 - `oneof=bar baz` will be applied to each string in the inner slice. 165 166 ### `keys` and `endkeys` 167 168 These tags are used to validate the keys of a map. For instance, the following 169 would be valid config for a map valued field (`map[string]string`) tagged with 170 `min=1,dive,keys,eq=1|eq=2,endkeys,required`. 171 172 ```json 173 { 174 "foo": { 175 "1": "bar", 176 "2": "baz", 177 }, 178 } 179 ``` 180 181 - `min=1` will be applied to the map itself 182 - `eq=1|eq=2` will be applied to the map keys 183 - `required` will be applied to map values