Block isolation breaches and bind frozen replay to scheduled steps

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e76f-be98-7ae3-965d-e0b31290a4c4
This commit is contained in:
tegwick 2026-09-28 12:41:23 +02:00
parent a8bb787d12
commit 9cdade2116
10 changed files with 229 additions and 14 deletions

View file

@ -0,0 +1,110 @@
"""Framework isolation and frozen schedule identity are acceptance boundaries."""
from copy import deepcopy
from dataclasses import replace
import json
import pytest
from scenarios.alice_bob_carol import build
from testdriver import Runner, Verdict
from testdriver.actions import SemanticAction
from testdriver.classification import classify
from testdriver.crystallization import CrystallizedDriver, Trajectory, assess_stability
from testdriver.drivers import CompositeDriver
from testdriver.scenario import Step
@pytest.mark.parametrize('leak_at', [None, 0, 1, 2])
def test_isolation_breach_stops_run_and_cannot_be_accepted_or_frozen(leak_at):
world, driver, observer, asset, oracle = build()
calls = []
def leak():
world.cast['bob'].remember('overheard', world.cast['alice'].canary)
class LeakingDriver:
def realize(self, actor, action):
result = driver.realize(actor, action)
calls.append(action.name)
if len(calls) - 1 == leak_at:
leak()
return result
if leak_at is None:
leak()
result = Runner(world, LeakingDriver(), observer, oracle).run(asset)
assert result.verdict is Verdict.INCONCLUSIVE
assert len(calls) == (0 if leak_at is None else leak_at + 1)
assert any(j.verdict is Verdict.INCONCLUSIVE for j in result.judgments)
pack = json.loads(result.evidence.to_json())
assert any(o['data']['violations'] for o in pack['observations']
if o['kind'] == 'actor_isolation')
assert not classify(pack, pack).safe_to_accept
assert not assess_stability([pack, deepcopy(pack), deepcopy(pack)]).stable
@pytest.mark.parametrize('damage', ['violation', 'missing', 'stratum', 'duplicate', 'malformed'])
def test_passing_product_verdicts_cannot_hide_invalid_isolation_evidence(damage):
packs = []
for _ in range(3):
world, driver, observer, asset, oracle = build()
pack = json.loads(Runner(world, driver, observer, oracle).run(asset).evidence.to_json())
guard = [o for o in pack['observations'] if o['kind'] == 'actor_isolation'][-1]
if damage == 'violation':
guard['data']['violations'] = ['actor leaked']
elif damage == 'missing':
pack['observations'].remove(guard)
elif damage == 'stratum':
guard['stratum'] = 'S1'
elif damage == 'duplicate':
pack['observations'].append(deepcopy(guard))
else:
guard['data'].pop('violations')
assert all(v['verdict'] == 'PASS' for v in pack['verdicts'])
assert not classify(pack, pack).safe_to_accept
packs.append(pack)
assert not assess_stability(packs).stable
def trajectories():
return [Trajectory('a', 'grant_access', 'browser', '/resources/A/grant', ('subject_id',)),
Trajectory('b', 'grant_access', 'browser', '/resources/B/grant', ('subject_id',))]
@pytest.mark.parametrize('composite', [False, True])
def test_runner_replays_repeated_actions_by_step_and_can_reuse_driver(composite):
world, _, observer, asset, oracle = build()
calls = []
class Session:
def post_form(self, path, fields):
calls.append((path, fields))
return 200, ''
driver = CrystallizedDriver(trajectories(), lambda actor: Session())
if composite:
driver = CompositeDriver({'browser': driver}, 'browser')
asset.scenario = replace(asset.scenario, steps=tuple(
Step(step_id, 'alice', SemanticAction('grant_access', {'subject_id': subject},
frozenset({'browser'})))
for step_id, subject in [('a', 'bob'), ('b', 'carol')]
))
for _ in range(2):
Runner(world, driver, observer, oracle).run(asset)
assert calls == [('/resources/A/grant', {'subject_id': 'bob'}),
('/resources/B/grant', {'subject_id': 'carol'})] * 2
def test_ambiguous_unknown_and_mismatched_frozen_actions_do_not_send_requests():
world, _, _, _, _ = build()
def unexpected_session(actor):
pytest.fail('invalid frozen dispatch must not open a session')
driver = CrystallizedDriver(trajectories(), unexpected_session)
action = SemanticAction('grant_access', {}, frozenset({'browser'}))
assert driver.realize(world.cast['alice'], action).raised
assert driver.realize_step(world.cast['alice'], 'unknown', action).raised
assert driver.realize_step(world.cast['alice'], 'a', replace(action, name='revoke_access')).raised
with pytest.raises(ValueError, match='duplicate'):
CrystallizedDriver([trajectories()[0]] * 2, unexpected_session)