"""Exercise real owner contracts offline, with no service or credential access. EMERGENT_OWNER_ROOT=/path/to/checkouts enables the optional peer contract suite. Tests use a synthetic intake grant, not a registration or authenticated identity. """ import importlib import json import os from pathlib import Path import shutil import sys import pytest ROOT = Path(__file__).resolve().parents[1] @pytest.fixture def intake(): parent = os.environ.get('EMERGENT_OWNER_ROOT') if not parent: pytest.skip('set EMERGENT_OWNER_ROOT for real owner-contract checks') sys.path.insert(0, str(Path(parent) / 'informed-decision')) return importlib.import_module('informed_decision.intake') @pytest.fixture def envelope(): return json.loads((ROOT / 'docs/decisions/profile-adoption-intake.draft.json').read_text()) def validate(intake, envelope, grant=True): return intake.validate_submission(envelope, submitter_id='offline-test', grant=( intake.SubmitterGrant('offline-test', frozenset({'knowledge-profile'}), frozenset({'net-kingdom-admins'})) if grant else None)) def test_real_owner_accepts_unsigned_draft_with_synthetic_test_grant(intake, envelope): result = validate(intake, envelope) assert result.approval_binding['actor'] == 'informed-decision' assert result.memo.approval_id is None assert result.serves['resolves'] == 'never' def test_real_owner_requires_external_submitter_admission(intake, envelope): with pytest.raises(intake.IntakeRefused, match='submitter_unknown'): validate(intake, envelope, grant=False) @pytest.mark.parametrize('mutation,reason', [ ('packet', 'packet_digest_mismatch'), ('human', 'principal_prebound'), ('approval', 'approval_pinned_by_submitter'), ('actor', 'unknown_field'), ]) def test_real_owner_refuses_forged_handoff(intake, envelope, mutation, reason): if mutation == 'packet': envelope['packet'][0]['content'] += '\nChanged consequences.' elif mutation == 'human': envelope['memo']['binding']['principal']['id'] = 'asserted-human' elif mutation == 'approval': envelope['memo']['approval_id'] = '00000000-0000-0000-0000-000000000000' else: envelope['approval_intent']['actor'] = 'agent' with pytest.raises(intake.IntakeRefused, match=reason): validate(intake, envelope) @pytest.fixture def runbook(tmp_path): parent = os.environ.get('EMERGENT_OWNER_ROOT') if not parent: pytest.skip('set EMERGENT_OWNER_ROOT for real owner-contract checks') sys.path.insert(0, str(Path(parent) / 'runbook-tutorials')) pack_module = importlib.import_module('rtut.pack') run2 = importlib.import_module('rtut.run2') path = tmp_path / 'runbooks/security-orientation' shutil.copytree(ROOT / 'runbooks/security-orientation', path) pack = pack_module.load(path / 'pack.yaml') assert pack.ok, pack.errors return pack, run2 def test_real_engine_cannot_auto_confirm_orientation(runbook): pack, run2 = runbook run = run2.create(pack, 'offline-test', values=dict(task_ref='fixture',target_ref='non-tenant-fixture',environment='rehearsal'), mode='auto-confirm') result = run2.auto_confirm_tick(run) assert result['action'] == 'awaiting-operator' assert run.data['steps']['read-context']['state'] == 'todo' def test_real_engine_refuses_handoff_without_context(runbook): pack, run2 = runbook run = run2.create(pack, 'offline-test') with pytest.raises(run2.RunError): run2.start(run, 'prepare-question') with pytest.raises(run2.RunError): run2.start(run, 'record-handoff') def test_real_engine_requires_evidence_even_after_manual_check(runbook): pack, run2 = runbook run = run2.create(pack, 'offline-test', values=dict(task_ref='fixture',target_ref='non-tenant-fixture',environment='rehearsal')) run2.start(run, 'read-context') run2.verify(run, 'read-context', manual_ok=True) with pytest.raises(run2.RunError): run2.complete(run, 'read-context') run2.complete(run, 'read-context', evidence=dict(knowledge_receipt_ref='fixture:knowledge',scope_evidence_ref='fixture:scope')) assert run.data['steps']['read-context']['state'] == 'done'