specs/TrustServiceOnboarding.md defines the mechanism: a Phase Manifest file is committed to the declaring repo (durable, independently foldable forever) and separately registered with the hosted service; once registered, the Ledger's live authoritative copy is the hosted service only, not a second competing file. Licensor token bootstrapping is explicitly out of scope here (a WP-0008-T01 governance action). scripts/trf_onboard.py: a dependency-light CLI (stdlib urllib + target_revenue.validation only, no FastAPI/psycopg needed to onboard a Phase) with validate/register-phase/append-entry/status subcommands. The Licensor token is read only from a named environment variable, never accepted as a literal argument. tests/test_trf_onboard.py (4 tests, no network/Docker) proves invalid-manifest and missing-token-env cases fail before any HTTP attempt, by monkeypatching the request function to raise if called. tests/test_onboarding_hosted.py (1 Docker-gated test) runs an actual uvicorn server on a real socket and drives the full register -> append -> status round trip through the CLI as an external repo would invoke it.
87 lines
2.9 KiB
Python
87 lines
2.9 KiB
Python
"""Pure, offline tests for scripts/trf_onboard.py (WP-0006-T07).
|
|
|
|
No network call is made in these tests — they verify the offline
|
|
pre-flight validation short-circuits before any HTTP attempt, and that a
|
|
missing token env var fails loudly rather than silently sending an
|
|
unauthenticated request.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from conftest import golden_manifest
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
_SPEC = importlib.util.spec_from_file_location("trf_onboard", REPO_ROOT / "scripts" / "trf_onboard.py")
|
|
trf_onboard = importlib.util.module_from_spec(_SPEC)
|
|
_SPEC.loader.exec_module(trf_onboard)
|
|
|
|
|
|
def test_validate_accepts_golden_manifest(tmp_path, capsys):
|
|
manifest_path = tmp_path / "manifest.json"
|
|
manifest_path.write_text(json.dumps(golden_manifest()), encoding="utf-8")
|
|
|
|
trf_onboard.main(["validate", str(manifest_path)])
|
|
|
|
assert "OK" in capsys.readouterr().out
|
|
|
|
|
|
def test_validate_rejects_broken_manifest(tmp_path):
|
|
broken = golden_manifest()
|
|
del broken["phase"]["initial_target"]
|
|
manifest_path = tmp_path / "manifest.json"
|
|
manifest_path.write_text(json.dumps(broken), encoding="utf-8")
|
|
|
|
with pytest.raises(SystemExit):
|
|
trf_onboard.main(["validate", str(manifest_path)])
|
|
|
|
|
|
def test_register_phase_rejects_offline_before_any_network_call(tmp_path, monkeypatch):
|
|
"""A non-conformant manifest must be caught by the offline check —
|
|
_request must never be called at all."""
|
|
broken = golden_manifest()
|
|
del broken["phase"]["initial_target"]
|
|
manifest_path = tmp_path / "manifest.json"
|
|
manifest_path.write_text(json.dumps(broken), encoding="utf-8")
|
|
|
|
def _boom(*args, **kwargs):
|
|
raise AssertionError("no network call should have been made")
|
|
|
|
monkeypatch.setattr(trf_onboard, "_request", _boom)
|
|
monkeypatch.setenv("TRF_TEST_TOKEN", "irrelevant")
|
|
|
|
with pytest.raises(SystemExit):
|
|
trf_onboard.main(
|
|
[
|
|
"register-phase",
|
|
"--url", "http://example.invalid",
|
|
"--token-env", "TRF_TEST_TOKEN",
|
|
"--manifest", str(manifest_path),
|
|
]
|
|
)
|
|
|
|
|
|
def test_register_phase_requires_token_env_to_be_set(tmp_path, monkeypatch):
|
|
manifest_path = tmp_path / "manifest.json"
|
|
manifest_path.write_text(json.dumps(golden_manifest()), encoding="utf-8")
|
|
monkeypatch.delenv("TRF_TEST_TOKEN_UNSET", raising=False)
|
|
|
|
def _boom(*args, **kwargs):
|
|
raise AssertionError("no network call should have been made without a token")
|
|
|
|
monkeypatch.setattr(trf_onboard, "_request", _boom)
|
|
|
|
with pytest.raises(SystemExit, match="TRF_TEST_TOKEN_UNSET"):
|
|
trf_onboard.main(
|
|
[
|
|
"register-phase",
|
|
"--url", "http://example.invalid",
|
|
"--token-env", "TRF_TEST_TOKEN_UNSET",
|
|
"--manifest", str(manifest_path),
|
|
]
|
|
)
|