Skip to content

πŸ—οΈ Resolve WS_* env defaults from env.reference.yaml#12

Merged
bdsoha merged 6 commits into
mainfrom
feature/show-env
May 10, 2026
Merged

πŸ—οΈ Resolve WS_* env defaults from env.reference.yaml#12
bdsoha merged 6 commits into
mainfrom
feature/show-env

Conversation

@bdsoha
Copy link
Copy Markdown
Member

@bdsoha bdsoha commented May 10, 2026

Summary

  • New internals/config/{envref,resolve,format}.go parses env.reference.yaml once per process (path-keyed cache, auto-invalidates on WS__INTERNAL_ENV_REFERENCE override). Exposes Resolve(group, prop) for internal callers and ResolveKey(runtimeKey) for the CLI surface, with typed sugars for bool/int/list. Deprecation chains collapse transitively to the canonical target; cycles rejected.
  • New ws-cli show env <KEY> subcommand under the existing show family β€” flags --raw|--list|--bool|--int|--check. Stderr deprecation lines match the retired Python entrypoint/check-deprecated-env byte-for-byte so bash callers grepping the existing strings keep working. Exit codes for --check: 0 preferred set / 1 deprecated only or unset / 2 both set.
  • Existing const-driven callsites in cmd/feature, cmd/show/path, internals/{logger,metrics,secrets} swept onto the resolver. The user-facing Env*/Default* env-default consts in internals/config/defaults.go are deleted; WS__INTERNAL_* namespace stays out of scope as ws-cli's wiring layer.

Why

Today every WS_* default exists in two places: env.reference.yaml (the canonical schema) and internals/config/defaults.go as Go consts. Drift is a question of when, not if. This PR moves ws-cli to read defaults at runtime from the YAML, which becomes the single source of truth.

This is phase 1 of a two-phase rollout (lockstep-ws-cli):

  • Phase 1 (this PR): ws-cli ships the resolver + show env subcommand + tagged release.
  • Phase 2 (separate PR in workspace): env.reference.yaml schema gains delimiter: field; common.sh:check_env_set rewires to delegate to ws-cli show env --check; Python entrypoint/check-deprecated-env retires.

Test plan

  • go test ./... β€” all packages green (full Vera matrix in internals/config/resolve_test.go: bool truthy/falsy variants, int boundaries + overflow, list whitespace + unicode + delimiter overrides, deprecation chain collapse + cycle rejection, warn-once + byte-for-byte stderr).
  • cmd/show/show_test.go extended for show env flag dispatch, exit codes, mutually-exclusive flags, fixture-driven YAML loading via t.Setenv + t.TempDir() (path-keyed cache invalidates without test-only reset hooks).
  • go vet ./... clean.
  • pre-commit run --all-files clean.
  • Manually verify ws-cli show env WS_SERVER_ROOT --raw against a running workspace once merged + tagged.

Out of scope (deferred to phase 2)

  • env.reference.yaml delimiter: schema field + WS__INTERNAL_ENV_REFERENCE declaration.
  • workspace/src/build/dependencies/dependencies.yaml ws-cli version: bump (Renovate will open it once v0.0.51 is tagged).
  • common.sh:check_env_set rewire.
  • Python entrypoint/check-deprecated-env retirement.

AC 5 audit (non-test)

rg '"WS_[A-Z_]+"' ws-cli/{cmd,internals} excluding *_test.go: 4 documented exceptions β€”

  • internals/config/defaults.go β€” EnvIPCSocket (transitional; _internal: namespace stays as Go const).
  • internals/config/envref.go β€” os.Getenv("WS__INTERNAL_ENV_REFERENCE") loader bootstrap.
  • internals/secrets/{key.go, vault.go} β€” two os.LookupEnv calls preserving "user-misconfig produces specific error" / "env-set bypasses default file-existence check" semantics from the original code.

bdsoha added 6 commits May 10, 2026 16:28
Adds `IsWorkspace()` and `RequireWorkspace()` to `internals/config` using
the image-baked manifest as the detection signal, then wires a single
`PersistentPreRunE` on the root command so every subcommand exits 1 with a
styled error when run outside the workspace.
Single source of truth for every `WS_*` var moves to
`env.reference.yaml`. New `internals/config/{envref,resolve,format}.go`
parses the YAML once per process (path-keyed cache), exposes
`Resolve(group, prop)` for internal callers and `ResolveKey(runtimeKey)`
for the CLI surface, with typed sugars for bool/int/list. Deprecation
chains collapse transitively to the canonical target; cycles are
rejected. New `ws-cli show env <KEY>` subcommand under the existing
`show` family resolves env values for shell consumption with
`--raw|--list|--bool|--int|--check` flags. Existing const-driven
callsites in `cmd/feature`, `cmd/show/path`, `internals/{logger,
metrics,secrets}` swept onto the resolver. `WS__INTERNAL_*` namespace
stays out of scope as ws-cli's internal wiring layer.
`(*EnvReference).Resolve` returns just `string` (it never errored).
Drop the local `defaultEnvReferencePath` const β€” moved into
`internals/config/defaults.go` alongside the other path constants.
Reuse `env.String` for env lookups in the resolver chain and `Check`.
Collapse the four nested `yaml*` intermediate types into one anonymous
struct in `parseEnvReference`. Switch-based `ParseBool` replaces the
two package-level truthy/falsy maps.
`MustResolve(group, prop)` panics on YAML-load failure. Use it in
callers without fallback semantics β€” `cmd/show/path.go`,
`internals/logger/logger.go`, `internals/metrics/system.go` β€”
where missing YAML means the workspace is fundamentally broken
anyway. Multi-branch fallback paths in `internals/secrets/{key,
vault}.go` keep the error-returning `Resolve` form.

`cmd/root.go`'s `PersistentPreRunE` eager-loads the YAML alongside
`RequireWorkspace()` so YAML failure surfaces once at startup
through cobra's error path, not deep inside random commands.

`ResolveKey` short-circuits when the env var is set explicitly β€”
avoids loading the YAML when callers don't actually need the
default lookup. Lets tests that set every env var run without
installing a YAML fixture.
@bdsoha bdsoha merged commit 903cc08 into main May 10, 2026
3 checks passed
@bdsoha bdsoha deleted the feature/show-env branch May 10, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant