Refuse config keys that no setting has (closes #419)
check / check (push) Successful in 9m24s

config.Parse walks the file as written and fails on the first key that
matches no setting, naming its dotted path and line, so a typo in
exclude or prune_grace_period no longer falls back silently. Keys that a
${...} reference brings in are checked once smartconfig has filled it
in, and named without a line. YAML merge keys and a top-level env
section, which smartconfig reads, still load; an anchor that contains
itself is an error, and each anchored map is checked once per type.
config set refuses such a key before writing, with the same error, and
sets a key under env like any other value. The key-to-field lookup
moves from internal/cli to config.SettingType so both use it.

Model: opus-5-5
This commit is contained in:
sneak committed 2026-11-11 03:17:04 +00:00
1 parent 0d0c76fa24
commit 26914097a1
6 files changed
+462 -47

No files matched your search

+25 -2
View File
@@ -9,6 +9,7 @@ import (
"fmt"
"os"
"path/filepath"
"reflect"
"sort"
"strings"
"time"
@@ -286,15 +287,37 @@ func Load(path string) (*Config, error) {
}
// Parse reads YAML config data as Load does, without validating it. It
// applies default values for optional fields, fills in ${...} references
// using smartconfig, and expands ~ in paths.
// refuses a key that no setting has, applies default values for optional
// fields, fills in ${...} references using smartconfig, and expands ~ in
// paths.
func Parse(data []byte) (*Config, error) {
// smartconfig drops line numbers, so keys are checked in the data as
// written.
var root yaml.Node
err := yaml.Unmarshal(data, &root)
if err != nil {
return nil, fmt.Errorf("failed to parse config: %w", err)
}
err = checkKeys(&root, reflect.TypeFor[Config](), "",
map[*yaml.Node]bool{}, map[nodeAndType]bool{})
if err != nil {
return nil, err
}
// Load config using smartconfig for interpolation
sc, err := smartconfig.NewFromReader(bytes.NewReader(data))
if err != nil {
return nil, fmt.Errorf("failed to load config file: %w", err)
}
// A ${...} reference can bring in keys that are not in the file.
err = checkFilledKeys(sc.Data())
if err != nil {
return nil, err
}
cfg := &Config{
// Set defaults
BlobSizeLimit: defaultBlobSizeLimit,