refactor(config): canonical schema with `config set` validation

Summary

Closes #8335 (closed).

Replace the YAML lock file and the assorted manual switches with a single declarative KeyDef registry in internal/config/schema.go. The schema is the single source of truth for every configuration concern. As a user-facing consequence, glab config set now rejects keys that aren't registered — so plausible-looking-but-nonexistent keys (such as the oauth_scopes example from #8334 (closed)) can no longer be silently written to the config file.

What the schema drives

A single KeyDef entry per key now feeds:

  • the blank-config tree returned by NewBlankConfig (what gets written on first run);
  • validation in glab config set (KnownKeys / IsKnownKey);
  • per-key default values (defaultFor, gated by KeyDef.Fallback);
  • legacy-alias resolution (ConfigKeyEquivalence);
  • environment-variable resolution (EnvKeyEquivalence), with CI-autologin overrides layered on top;
  • keyring eligibility for sensitive values.

Internal-state keys (oauth2_*, is_oauth2, refresh_token) are explicit KeyDef entries with UserSettable: false. They're still recognized by Get and env-var lookups but excluded from the blank config and from config set.

What was removed

  • internal/config/config.yaml.lock — the YAML template is replaced by the schema.
  • internal/config/config_stub.go and internal/config/gen.go — no codegen step; the runtime builds the blank-config tree from KeySchema.
  • The gen-config Makefile target.
  • The chmod 600 internal/config/config.yaml.lock workaround in .gitlab-ci.yml.
  • The AST-based drift test. The schema-in-Go shape makes the drift problem impossible at the language level: a cfg.Get("", "new_key") without a matching KeyDef has no env-var resolution, no default, and is rejected by config set — no parsing needed.
  • The hand-maintained switches in config_mapping.go (ConfigKeyEquivalence, EnvKeyEquivalence, defaultFor) and the keyringEligibleKeys map in config.go — all derived from the schema now.
  • internal/config/Readme.md — non-standard location, no inbound links; replaced by KeyDef doc comments and a pointer in AGENTS.md.

What was updated alongside

  • .gitlab/duo/mr-review-instructions.yaml — the "Config and environment" block referenced the lock file and make gen-config; it now points contributors at KeySchema in internal/config/schema.go.
  • AGENTS.md — added a one-line pointer to internal/config/schema.go in the existing "helpers" list under "Working in this codebase".

Adding a new key

Append a KeyDef to KeySchema:

{
    Name:         "my_new_key",
    Scope:        ScopeGlobal,   // or ScopePerHost
    Type:         TypeString,    // or TypeBool, TypeList
    Default:      "",
    Description:  "What this key controls. Becomes the head comment.",
    UserSettable: true,
},

No code generation, no file-permission dance, no out-of-band drift check.

Test plan

  • make test passes
  • make lint passes
  • glab config set oauth_scopes "openid profile" errors with the new message
  • glab config set editor vim still works
  • All env-var lookups still resolve (e.g. GITLAB_TOKEN, CI_JOB_TOKEN in CI auto-login mode)
  • glab reads defaults for git_protocol, api_protocol, and glamour_style when the user's config has no entry (the keys with Fallback: true)
  • CI's check_go_generated_code job passes (no more chmod step against the deleted lock file)
Edited by Kai Armstrong

Merge request reports

Loading