import sqlite3 import pytest from src.passkey_store import PasskeyStore from src.session_store import SessionStore, SessionStoreError def test_global_access_revocation_rolls_back_every_credential_and_session_change(tmp_path): database = tmp_path / "sessions.sqlite3" sessions = SessionStore(database, clock=lambda: 1_000.0) sessions.activate( "phone-session", 2_000, management_id="phone-management-id", device_label="Phone", ) sessions.mint_step_up( "phone-session", action="revoke_all_sessions", target="all", ttl_seconds=90, ) passkeys = PasskeyStore(database, clock=lambda: 1_000.0) passkeys.register( credential_id=b"phone-credential", public_key=b"phone-public-key", sign_count=0, device_label="Phone", management_id="phone-management-id", ) passkeys.issue_challenge( b"pending-challenge", session_id="phone-session", purpose="authentication", action="sign_in", target="dashboard", ) with sqlite3.connect(database) as connection: connection.execute( "CREATE TRIGGER block_session_delete BEFORE DELETE ON active_sessions " "BEGIN SELECT RAISE(ABORT, 'injected failure'); END" ) with pytest.raises(SessionStoreError): passkeys.revoke_all_access() with sqlite3.connect(database) as connection: assert connection.execute("SELECT COUNT(*) FROM passkey_credentials").fetchone() == (1,) assert connection.execute("SELECT COUNT(*) FROM passkey_challenges").fetchone() == (1,) assert connection.execute("SELECT COUNT(*) FROM step_up_grants").fetchone() == (1,) assert connection.execute("SELECT COUNT(*) FROM active_sessions").fetchone() == (1,) def test_device_access_revocation_rolls_back_target_and_preserves_other_devices(tmp_path): database = tmp_path / "sessions.sqlite3" sessions = SessionStore(database, clock=lambda: 1_000.0) passkeys = PasskeyStore(database, clock=lambda: 1_000.0) for label in ("Phone", "Laptop"): slug = label.lower() sessions.activate( f"{slug}-session", 2_000, management_id=f"{slug}-management-id", device_label=label, ) sessions.mint_step_up( f"{slug}-session", action="close_issue", target="stackchain/dashboard#1", ttl_seconds=90, ) passkeys.register( credential_id=f"{slug}-credential".encode(), public_key=f"{slug}-public-key".encode(), sign_count=0, device_label=label, management_id=f"{slug}-management-id", ) with sqlite3.connect(database) as connection: connection.execute( "CREATE TRIGGER block_phone_delete BEFORE DELETE ON active_sessions " "WHEN OLD.management_id = 'phone-management-id' " "BEGIN SELECT RAISE(ABORT, 'injected failure'); END" ) with pytest.raises(SessionStoreError): passkeys.revoke_device_access("phone-management-id") with sqlite3.connect(database) as connection: assert connection.execute( "SELECT management_id FROM active_sessions ORDER BY management_id" ).fetchall() == [("laptop-management-id",), ("phone-management-id",)] assert connection.execute( "SELECT management_id FROM passkey_credentials ORDER BY management_id" ).fetchall() == [("laptop-management-id",), ("phone-management-id",)] assert connection.execute("SELECT COUNT(*) FROM step_up_grants").fetchone() == (2,)