Skip to main content

Module env_ref

Module env_ref 

Source
Expand description

The ${VAR} / env:VAR reference grammar — the ONE parse chokepoint every env-reference path in the toolkit shares (credentials, token_secret, and [backend].base_url).

Deliberately carries NO #[cfg(feature = ...)] gate: the function used to live inside the feature-gated http module, which made “the toolkit’s universal chokepoint” true only in http builds.

pub rather than pub(crate) (plan 120-05): the grammar is duplicated by necessity in pmcp-package — the workspace-excluded leaf crate, which neither may depend on this one nor be depended on by it — and the two implementations are held to a shared accept/reject table asserted from an INTEGRATION test in each crate. An integration test is an external consumer, so the reference implementation has to be reachable from outside the crate for that parity claim to be checkable at all. The ONE place the ${VAR} / env:VAR reference grammar is defined for the whole toolkit.

Every path that reads an operator-supplied value which MAY be an environment reference routes through [parse_env_ref]:

  • outgoing credentials ([backend.auth] api_key / bearer token / basic password / oauth2 client_secret) — crate::http::auth;
  • [code_mode] token_secret — crate::code_mode;
  • [backend] base_url — crate::config::BackendSection::resolved_base_url.

§Why this module is NOT feature-gated

The function previously lived as a private helper inside crate::http::auth, and the whole http module is #[cfg(feature = "http")]. It compiled (BackendSection is itself http-gated), but the accompanying claim — “the single chokepoint every env-reference path shares” — was reachable only in http builds, so it was architecturally false. Packaging tooling is about to build a cross-crate grammar-parity claim on top of that statement, so the statement has to be structurally true rather than aspirational: this module carries NO #[cfg(feature = ...)] gate and compiles in every feature configuration.

§Grammar

InputResultMeaning
env:VARSome("VAR")reference
${VAR}Some("VAR")reference (VAR must match [A-Za-z0-9_]+)
${}Some("")MALFORMED reference — a reference to an empty name
${A}://${B}Some("")MALFORMED reference — a multi-placeholder composition
${VARNoneunterminated → a plain literal
plainNoneplain literal

The malformed-means-empty rule is deliberate: the empty name is the signal that a value is reference-SHAPED but names nothing, so no caller ships the literal ${...} text to the wire. A ${...} value is a reference to exactly ONE variable — the grammar does not interpolate inside a larger string, so a composition like ${SCHEME}://${HOST} names nothing any environment could set; compose the full value in one variable instead.

§Callers diverge on UNSET, agree on MALFORMED, never diverge on PARSING

Two different questions, two different answers:

  • Unset variable (Some("VAR"), VAR not exported) — caller policy, and it legitimately differs. A credential resolves it to the empty string so an OPTIONAL credential is omitted; an endpoint errors, because an empty endpoint is not a degraded request but a broken one.
  • Malformed reference (Some("")) — NOT caller policy. Every caller refuses it, because no environment could ever satisfy it, so “omit” would mean silently proceeding without a value the operator believed they had supplied. The credential path once applied the unset rule here, which made token = "${GITHUB-PAT}" send every backend request unauthenticated with no error and no log line; it is now refused at load time (crate::error::ConfigValidationError::MalformedBackendAuthRef) and at provider-build time, matching base_url’s crate::error::ConfigValidationError::MalformedBackendBaseUrlRef.

What must NOT differ is the PARSE: a second ${} parser with slightly different edge cases is a latent security bug (one parser treating ${VAR as a reference and another as a literal is exactly how a placeholder reaches the wire).

Note that pmcp-package deliberately DUPLICATES this grammar rather than depending on the toolkit — that crate is the workspace-excluded leaf and a dependency in either direction inverts the layering. The duplication is kept honest by a package-side grammar-parity table, not by a shared type.

Functions§

is_valid_env_var_name
Whether name is a variable name a target environment can actually be told to set: non-empty, ASCII alphanumerics and _ only — the portable intersection of POSIX shells, env files, and container manifests.
parse_env_ref
The single brace/env-ref parse core shared by EVERY credential-resolution path (api_key, bearer token, basic password, oauth2 client_secret).