Repository: caddyserver/caddy (language: go)

Issue:
Bug in config validator
Config

```
# cat /etc/caddy/caddy.json
{
    "admin": {
        "disable": false,
        "listen": "0.0.0.0:8000"
    }
}
```

Validation is ok

```
# /usr/local/bin/caddy validate --config /etc/caddy/caddy.json
2023/02/19 20:23:56.220 INFO    using provided configuration    {"config_file": "/etc/caddy/caddy.json", "config_adapter": ""}
Valid configuration
```

Run is error

```
# /usr/local/bin/caddy run --config /etc/caddy/caddy.json
2023/02/19 20:24:08.955 INFO    using provided configuration    {"config_file": "/etc/caddy/caddy.json", "config_adapter": ""}
Error: loading initial config: loading new config: json: unknown field "disable"
```

Caddy version

```
# /usr/local/bin/caddy version
v2.6.3 h1:QRVBNIqfpqZ1eJacY44I6eUC1OcxQ8D04EKImzpj7S8=
```



Discussion / hints:

Fix patch:
diff --git a/caddy.go b/caddy.go
index 5d0152a768e..84cfc11cfbb 100644
--- a/caddy.go
+++ b/caddy.go
@@ -314,7 +314,7 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
 	strippedCfgJSON := RemoveMetaFields(cfgJSON)
 
 	var newCfg *Config
-	err := strictUnmarshalJSON(strippedCfgJSON, &newCfg)
+	err := StrictUnmarshalJSON(strippedCfgJSON, &newCfg)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/commandfuncs.go b/cmd/commandfuncs.go
index 62afae2bb54..cc5666bb1e6 100644
--- a/cmd/commandfuncs.go
+++ b/cmd/commandfuncs.go
@@ -490,7 +490,7 @@ func cmdAdaptConfig(fl Flags) (int, error) {
 	// validate output if requested
 	if adaptCmdValidateFlag {
 		var cfg *caddy.Config
-		err = json.Unmarshal(adaptedConfig, &cfg)
+		err = caddy.StrictUnmarshalJSON(adaptedConfig, &cfg)
 		if err != nil {
 			return caddy.ExitCodeFailedStartup, fmt.Errorf("decoding config: %v", err)
 		}
@@ -523,7 +523,7 @@ func cmdValidateConfig(fl Flags) (int, error) {
 	input = caddy.RemoveMetaFields(input)
 
 	var cfg *caddy.Config
-	err = json.Unmarshal(input, &cfg)
+	err = caddy.StrictUnmarshalJSON(input, &cfg)
 	if err != nil {
 		return caddy.ExitCodeFailedStartup, fmt.Errorf("decoding config: %v", err)
 	}
diff --git a/context.go b/context.go
index 330bfa6f5b0..c585aa55d2c 100644
--- a/context.go
+++ b/context.go
@@ -326,7 +326,7 @@ func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error
 
 	// fill in its config only if there is a config to fill in
 	if len(rawMsg) > 0 {
-		err := strictUnmarshalJSON(rawMsg, &val)
+		err := StrictUnmarshalJSON(rawMsg, &val)
 		if err != nil {
 			return nil, fmt.Errorf("decoding module config: %s: %v", modInfo, err)
 		}
diff --git a/modules.go b/modules.go
index e83bc747ea4..470c25e3725 100644
--- a/modules.go
+++ b/modules.go
@@ -333,11 +333,11 @@ func ParseStructTag(tag string) (map[string]string, error) {
 	return results, nil
 }
 
-// strictUnmarshalJSON is like json.Unmarshal but returns an error
+// StrictUnmarshalJSON is like json.Unmarshal but returns an error
 // if any of the fields are unrecognized. Useful when decoding
 // module configurations, where you want to be more sure they're
 // correct.
-func strictUnmarshalJSON(data []byte, v any) error {
+func StrictUnmarshalJSON(data []byte, v any) error {
 	dec := json.NewDecoder(bytes.NewReader(data))
 	dec.DisallowUnknownFields()
 	return dec.Decode(v)


Test patch: