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.
This commit is contained in:
parent
45b9fbd765
commit
ee4cf14cbc
6 changed files with 530 additions and 2 deletions
87
tests/test_trf_onboard.py
Normal file
87
tests/test_trf_onboard.py
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
"""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),
|
||||
]
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue