emergent-security/tests/test_owner_links.py
tegwick 445179edfa Link security knowledge to human decisions and guided runbooks
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a101af-e240-7882-a1e3-e37720cbdbea
2026-10-03 15:50:04 +02:00

107 lines
4.2 KiB
Python

"""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'