target-revenue/tests/test_trf_onboard.py
tegwick ee4cf14cbc Define and implement multi-repo onboarding mechanism (WP-0006-T07)
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.
2026-07-29 22:00:34 +02:00

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),
]
)