Files
computer-playbook/cli/administration/inventory/credentials/overrides.py
kevinveenbirkenbachandClaude Opus 5 f713ba8350 refactor(credentials): address them at secrets.credentials, like every other meta file
meta/schema.yml became meta/secrets.yml, but its content still landed at
applications.<app>.credentials — the one meta file whose payload did not sit
under a root named after the file. Every other topic obeys that rule:
meta/volumes.yml goes to volumes, meta/rbac.yml to rbac. Credentials now go to
secrets.credentials.

The path exists exactly once, in utils/manager/credential_key.py, and
OVERRIDE_SECTION is derived from its two segments rather than spelled beside
them, so the dotted form used by --set and the nested form used by the
inventory cannot drift. Six consumers read it: the loader, the generator, the
CLI override parser, the two emit helpers, and the four lookup validators.

--set now accepts exactly one key shape,
applications.<app>.secrets.credentials.<key>. The three short forms are
rejected instead of guessed at: the same short key names different credentials
on different apps. That also retired primary_app_id, which only existed to
disambiguate them.

Three defects surfaced while wiring this up. _apply_one_role_schema still wrote
to the old root, so an app's own credentials would have moved while its
providers' stayed behind. web-app-pgadmin reads through
lookup('applications', ...).credentials.<key>, an access path no regex over
lookup('config', ...) could see, and would have deployed with an empty postgres
password. And _META_NON_GENERIC_TOPICS still listed 'schema' — a bare topic
name, invisible to any path search — so the generic file-root loop assigned the
raw schema under secrets and the follow-up write landed inside the cached
document, truncating keycloak's four credentials to one for every later
reader.

tests/integration/ansible/lookups/config/test_credentials_roundtrip.py pins both
directions of the seam and the cache invariant that last defect broke.

Existing inventories still carry the pre-rename root; migrating them is
deliberately out of scope here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 16:51:56 +02:00

49 lines
1.5 KiB
Python

"""CLI ``--set`` override parsing and per-key resolution."""
from __future__ import annotations
from utils.manager.credential_key import (
OVERRIDE_ROOT,
OVERRIDE_SECTION,
override_key,
split_override_key,
)
__all__ = ["override_for", "override_key", "parse_overrides", "split_override_key"]
def parse_overrides(pairs: list[str]) -> dict[str, str]:
"""Parse ``--set <key>=<value>`` pairs into a dict.
Args:
pairs: raw ``key=value`` strings from the command line.
Every key MUST be the fully qualified form :func:`override_key` builds; a
short form is rejected rather than guessed at, because the same short key
names different credentials on different apps.
"""
out: dict[str, str] = {}
prefix = f"{OVERRIDE_ROOT}."
section = f".{OVERRIDE_SECTION}."
for pair in pairs:
raw_key, value = pair.split("=", 1)
key = raw_key.strip()
if not key.startswith(prefix) or section not in key:
raise SystemExit(
f"--set {key}: expected "
f"{OVERRIDE_ROOT}.<app_id>.{OVERRIDE_SECTION}.<key>=<value>"
)
out[key] = value.strip()
return out
def override_for(app_id: str, key: str, overrides: dict[str, str]) -> str | None:
"""The override value for one credential, or None when unset.
Args:
app_id: application the credential belongs to.
key: dotted path inside the schema's ``credentials`` node.
overrides: parsed ``--set`` pairs.
"""
return overrides.get(override_key(app_id, key))