mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
The asset lookup hardcoded https for the internal CDN origin, but .onion vhosts are plaintext with no 443 listener, and the dashboard mirror-rewrite sent even onion-local asset URLs through the mirror (404). The adapter never loaded, so the OIDC code was never exchanged and Login stayed visible after the round-trip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
81 lines
3.2 KiB
Python
81 lines
3.2 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from ansible.errors import AnsibleError
|
|
from ansible.plugins.loader import lookup_loader
|
|
from ansible.plugins.lookup import LookupBase
|
|
|
|
from plugins.filter.role_path_by_app_id import abs_role_path_by_application_id
|
|
from utils.cache.files import read_text
|
|
from utils.tls_common import is_onion_domain
|
|
|
|
_JSDELIVR = "https://cdn.jsdelivr.net"
|
|
|
|
|
|
def resolve_host(variables, loader, templar) -> str:
|
|
"""The asset host for the current deployment: the internal CDN origin
|
|
when web-svc-cdn is deployed with flavor internal, else jsdelivr."""
|
|
if "web-svc-cdn" not in (variables.get("group_names") or []):
|
|
return _JSDELIVR
|
|
flavor = lookup_loader.get("config", loader=loader, templar=templar).run(
|
|
["web-svc-cdn", "services.cdn.flavor"], variables=variables
|
|
)[0]
|
|
if str(flavor).strip().lower() != "internal":
|
|
return _JSDELIVR
|
|
domain = lookup_loader.get("domain", loader=loader, templar=templar).run(
|
|
["web-svc-cdn"], variables=variables
|
|
)[0]
|
|
scheme = "http" if is_onion_domain(domain) else "https"
|
|
return f"{scheme}://{domain}"
|
|
|
|
|
|
class LookupModule(LookupBase):
|
|
"""
|
|
Usage:
|
|
{{ lookup('asset', application_id, package, path_within_package) }}
|
|
|
|
Resolves a browser-facing URL for a frontend dependency declared in the
|
|
role's own package-lock.json, mirroring jsdelivr's npm path scheme so the
|
|
internal and external forms differ only by host:
|
|
|
|
internal (web-svc-cdn deployed, flavor internal):
|
|
cdn.<domain>/npm/<package>@<locked-version>/<path>
|
|
external (no web-svc-cdn, or flavor external):
|
|
cdn.jsdelivr.net/npm/<package>@<locked-version>/<path>
|
|
|
|
The version is read from roles/<application_id>/files/package-lock.json, so
|
|
the URL is always the exact pinned, lockfile-reproducible version.
|
|
"""
|
|
|
|
def run(self, terms, variables: dict[str, Any] | None = None, **kwargs):
|
|
if len(terms) != 3:
|
|
raise AnsibleError(
|
|
"lookup('asset', application_id, package, path) expects 3 terms"
|
|
)
|
|
application_id, package, path = (str(t) for t in terms)
|
|
variables = variables or getattr(self._templar, "available_variables", {}) or {}
|
|
|
|
version = self._locked_version(application_id, package)
|
|
host = resolve_host(variables, self._loader, getattr(self, "_templar", None))
|
|
return [f"{host}/npm/{package}@{version}/{path.lstrip('/')}"]
|
|
|
|
def _locked_version(self, application_id: str, package: str) -> str:
|
|
lock = (
|
|
Path(abs_role_path_by_application_id(application_id))
|
|
/ "files"
|
|
/ "package-lock.json"
|
|
)
|
|
if not lock.is_file():
|
|
raise AnsibleError(
|
|
f"lookup('asset'): {lock} not found; declare {package} in the "
|
|
f"role's files/package.json and commit its files/package-lock.json"
|
|
)
|
|
data = json.loads(read_text(str(lock)))
|
|
entry = (data.get("packages") or {}).get(f"node_modules/{package}")
|
|
if not entry or "version" not in entry:
|
|
raise AnsibleError(f"lookup('asset'): {package} not pinned in {lock}")
|
|
return str(entry["version"])
|