← Files Zuora Coding AgentARCHIVED FILE
references/uat-test/execution/scripts/tenant_resolve.py
5.93 KB · Oct 2, 2026 · 00:30 UTC
#!/usr/bin/env python3
"""Layered tenant resolution for zuora-uat verify/run (mcp default)."""
from __future__ import annotations
import argparse
import json
import os
import re
import sys
from pathlib import Path
SCRIPT_DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(SCRIPT_DIR.parent / "tests"))
from test_utils.uat_root import find_git_root, find_uat_root # noqa: E402
try:
import yaml
except ImportError:
yaml = None
def derive_ui_base_url(api_base_url: str) -> str:
url = api_base_url.rstrip("/")
url = re.sub(r"^https?://rest[-.]?", "https://", url)
url = re.sub(r"^https?://", "", url)
host = url.split("/")[0]
if host.startswith("rest-"):
host = host[5:]
elif host.startswith("rest."):
host = host[5:]
return f"https://{host}/apps"
def load_yaml(path: Path) -> dict | None:
if not path.is_file() or yaml is None:
return None
return yaml.safe_load(path.read_text(encoding="utf-8")) or {}
def mcp_env_config() -> dict | None:
base = os.environ.get("ZUORA_BASE_URL", "").strip()
client_id = os.environ.get("ZUORA_CLIENT_ID", "").strip()
client_secret = os.environ.get("ZUORA_CLIENT_SECRET", "").strip()
bearer = os.environ.get("ZUORA_BEARER_TOKEN", "").strip()
if bearer and base:
return {
"environment": "mcp",
"api_base_url": base,
"ui_base_url": derive_ui_base_url(base),
"authentication": {"type": "bearer", "token": bearer},
"has_ui_auth": False,
}
if base and client_id and client_secret:
return {
"environment": "mcp",
"api_base_url": base,
"ui_base_url": derive_ui_base_url(base),
"authentication": {
"type": "oauth",
"client_id": client_id,
"client_secret": client_secret,
"token_endpoint": "/oauth/token",
"grant_type": "client_credentials",
},
"has_ui_auth": False,
}
return None
def resolve(uat_root: Path, environment: str, tenant_suffix: str | None) -> dict:
local_path = uat_root / "execution" / "config" / "test_config.local.yaml"
committed_path = uat_root / "execution" / "config" / "test_config.yaml"
if environment == "mcp":
mcp = mcp_env_config()
if mcp:
return mcp
for cfg_path in (local_path, committed_path):
cfg = load_yaml(cfg_path)
if not cfg:
continue
envs = cfg.get("test_environments", {})
key = environment
if key in ("staging", "preprod") and key not in envs:
mcp = mcp_env_config()
if mcp:
return {**mcp, "warning": f"environment '{key}' not in config; using mcp"}
raise SystemExit(f"environment '{key}' not in test_config; use environment=mcp or add the key")
if key == "mcp":
mcp = mcp_env_config()
if mcp:
return mcp
default = cfg.get("default_environment", "staging")
key = default
if tenant_suffix and key in envs:
suffixed = f"{key}_{tenant_suffix}"
if suffixed in envs:
key = suffixed
if key not in envs:
raise SystemExit(f"environment '{environment}' not found in {cfg_path}")
env = envs[key]
has_ui = bool(env.get("ui_authentication") or cfg.get("ui_authentication"))
return {
"environment": key,
"api_base_url": env.get("api_base_url", env.get("rest_url", "")),
"ui_base_url": env.get("ui_base_url", ""),
"authentication": env.get("authentication", {}),
"has_ui_auth": has_ui,
"test_data": env.get("test_data", cfg.get("test_data", {})),
"config_path": str(cfg_path),
}
mcp = mcp_env_config()
if mcp:
return mcp
raise SystemExit(
"No tenant config found. Set ZUORA_BASE_URL + ZUORA_CLIENT_ID/SECRET (zuora-mcp) "
"or add uat/execution/config/test_config.yaml"
)
def scaffold_local(uat_root: Path) -> Path | None:
mcp = mcp_env_config()
if not mcp:
return None
target = uat_root / "execution" / "config" / "test_config.local.yaml"
if target.exists():
return target
target.parent.mkdir(parents=True, exist_ok=True)
content = {
"default_environment": "mcp",
"test_environments": {
"mcp": {
"api_base_url": mcp["api_base_url"],
"ui_base_url": mcp["ui_base_url"],
"authentication": mcp["authentication"],
}
},
}
target.write_text(
"# Auto-scaffolded from zuora-mcp env on first tenant touch.\n"
+ "# Add ui_authentication here for UI tests.\n"
+ yaml.safe_dump(content, sort_keys=False),
encoding="utf-8",
)
return target
def main():
parser = argparse.ArgumentParser(description="Resolve tenant for UAT verify/run")
parser.add_argument("--git-root", default=None, help="Git project root")
parser.add_argument("--repo-root", default=None, help="Deprecated: use --git-root")
parser.add_argument("--uat-root", default=None, help="UAT workspace root override")
parser.add_argument("--environment", default="mcp")
parser.add_argument("--tenant-suffix", default=None)
parser.add_argument("--scaffold-local", action="store_true")
args = parser.parse_args()
git_arg = args.git_root or args.repo_root
git = Path(git_arg).resolve() if git_arg else find_git_root()
uat = Path(args.uat_root).resolve() if args.uat_root else find_uat_root(git)
if args.scaffold_local:
scaffold_local(uat)
result = resolve(uat, args.environment, args.tenant_suffix)
result["uat_root"] = str(uat)
print(json.dumps(result, indent=2))
if result.get("environment"):
print(f"export TEST_ENVIRONMENT={result['environment']}", file=sys.stderr)
if __name__ == "__main__":
main()
SHA-256: 59c4c1fba7e2483819f2917629aa4d9a7e0893c8329094f243652276ad112688