Files
computer-playbook/roles/svc-ai-litellm/meta/secrets.yml
kevinveenbirkenbachandClaude Opus 5 15a6251d72 fix(api): resolve credentials against the declaration an inventory override hides
API is a plain mapping, so an inventory that configures three providers replaces the whole declaration from group_vars/all/18_api.yml instead of merging into it. inventories/development/default.yml declares openai, anthropic and openrouter, so github, google and jira did not exist in CI at all and lookup('api', 'github.client_id') raised.

A raising lookup inside a value the applications renderer is templating does not fail the render: _templar_render_best_effort returns the string untouched and, for a value carrying a non-env lookup(, refuses the fallback as well. The raw template text reached plugin_value.enabled | bool, which coerced it to False and emitted the deprecation warning that fails the deploy gate. Run 34893363518, job 104153194109 lost web-app-nextcloud to exactly that, for three integrations at once. The configvalue entries would have stored template text as the client id.

utils/api.py merges the scope's override over the declaration, so an override narrows values and never the provider set, and holds the enable rule: every credential a provider declares must carry a value. The api lookup reads through it; the new api_enabled lookup gates on it and returns a real boolean instead of a string a filter has to coerce.

The same class sat in group_vars/all/16_ai.yml and roles/svc-ai-litellm/meta/secrets.yml as bare API.<provider>.<key> dereferences; both now go through the lookups.

Two lints keep it shut. test_addon_enabled_renders_to_bool renders the whole applications map against a scope with API blanked, the most hostile override an inventory may legally write, and requires every addon gate to come out a boolean. test_api_accessed_via_lookup forbids a bare API dereference in Jinja under roles/, group_vars/ and inventories/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 03:35:47 +02:00

29 lines
1.2 KiB
YAML

---
credentials:
master_key:
description: "Admin master key of the LiteLLM gateway; consumers use per-consumer virtual keys, never this one"
algorithm: "alphanumeric"
validation:
min_length: 50
ui_password:
description: "Login password of the LiteLLM admin UI (served at /ui, proxied by web-app-litellm)"
algorithm: "alphanumeric"
validation:
min_length: 32
openai_api_key:
description: "OpenAI API key; empty leaves the openai/* models unpublished. The pattern rejects a truncated or whitespace-carrying paste, not a vendor prefix:
OpenAI moved from sk- to sk-proj- without notice, and a schema that pinned the prefix would reject a valid key"
type: "string"
regex: "\\S{20,}"
default: "{{ lookup('api', 'openai.api_key') }}"
anthropic_api_key:
description: "Anthropic API key; empty leaves the anthropic/* models unpublished"
type: "string"
regex: "\\S{20,}"
default: "{{ lookup('api', 'anthropic.api_key') }}"
openrouter_api_key:
description: "OpenRouter API key; empty leaves openrouter/auto unpublished"
type: "string"
regex: "\\S{20,}"
default: "{{ lookup('api', 'openrouter.api_key') }}"