Enforced connection fields can be overridden by a user's environment variables
Summary
The POSIT_AI_PROVIDERS_ENFORCED overlay is meant to be non-overridable. That holds for enablement and for connection fields set through config files, but not for the connection fields that have an environment-variable mapping. A user who sets an ordinary environment variable in their own shell (POSITAI_AUTH_HOST, ANTHROPIC_BASE_URL, OPENAI_BASE_URL, AWS_REGION, and the others in CONNECTION_ENV_MAPPINGS) overrides the enforced value for that field.
Admins set the ENFORCED overlay precisely to lock these fields, so a per-user workaround defeats the control's purpose.
Root cause
Connection config and enablement resolve on two different paths.
Enablement folds every source, enforced first, in resolveEnabled ("first defined wins," enforced on top) — sound.
Connection config takes a longer path in buildCatalog:
resolveConnection(id, block) // merges sources; enforced wins here
-> applyEnvOverlay(id, ..., envVars) // runs AFTER, unconditionally
applyEnvOverlay (build-catalog.ts:289) applies the environment overlay after the enforced merge, and its own contract states "Env vars have the highest precedence: env > file (providers.json) > defaults" (build-catalog.ts:285). The envVars it reads is plain process.env, injected by the node seam (load-catalog.ts:42), the same object for every user. The mapped variables in CONNECTION_ENV_MAPPINGS (build-catalog.ts:51) are ordinary environment variables, not the sealed POSIT_AI_PROVIDERS_ENFORCED fragment. Nothing between process.env and the overlay distinguishes an admin-set variable from a user-set one.
The layering is inverted: the environment overlay represents user/host intent but is applied above the admin's enforced layer.
The existing test "enforced connection can never be overridden by lower sources" (__tests__/resolve-catalog.test.ts:74) only exercises file and default sources with envVars: {}, so it never covers the environment path where the invariant fails.
Enforced connection fields can be overridden by a user's environment variables
Summary
The
POSIT_AI_PROVIDERS_ENFORCEDoverlay is meant to be non-overridable. That holds for enablement and for connection fields set through config files, but not for the connection fields that have an environment-variable mapping. A user who sets an ordinary environment variable in their own shell (POSITAI_AUTH_HOST,ANTHROPIC_BASE_URL,OPENAI_BASE_URL,AWS_REGION, and the others inCONNECTION_ENV_MAPPINGS) overrides the enforced value for that field.Admins set the
ENFORCEDoverlay precisely to lock these fields, so a per-user workaround defeats the control's purpose.Root cause
Connection config and enablement resolve on two different paths.
Enablement folds every source, enforced first, in
resolveEnabled("first defined wins," enforced on top) — sound.Connection config takes a longer path in
buildCatalog:applyEnvOverlay(build-catalog.ts:289) applies the environment overlay after the enforced merge, and its own contract states "Env vars have the highest precedence: env > file (providers.json) > defaults" (build-catalog.ts:285). TheenvVarsit reads is plainprocess.env, injected by the node seam (load-catalog.ts:42), the same object for every user. The mapped variables inCONNECTION_ENV_MAPPINGS(build-catalog.ts:51) are ordinary environment variables, not the sealedPOSIT_AI_PROVIDERS_ENFORCEDfragment. Nothing betweenprocess.envand the overlay distinguishes an admin-set variable from a user-set one.The layering is inverted: the environment overlay represents user/host intent but is applied above the admin's enforced layer.
The existing test "enforced connection can never be overridden by lower sources" (
__tests__/resolve-catalog.test.ts:74) only exercises file anddefaultsources withenvVars: {}, so it never covers the environment path where the invariant fails.