"""Shared test helpers. issue_code() requires a live agent session, so tests that mint codes have to prove key possession the same way production does rather than reaching past the boundary. These helpers do that so the tests stay readable. """ import base64 from sigil import identity, keys, viewcodes from sigil.store import Store def enrol(store, agent="bigpickle"): """Enrol agent with a fresh key. Returns (private, public).""" private, public = keys.generate() secret = identity.seed_bootstrap(store, agent) identity.enrol(store, agent, keys.export_public_b64(public), secret) return private, public def sign(private, nonce): return base64.b64encode(private.sign(nonce.encode())).decode() def agent_token(store, private, agent="bigpickle", limit=5000, window=60): """Full challenge-response, ending in a live agent session token. The rate limit is opened wide by default: tests that legitimately mint many codes should not trip the production quota. The quota itself is asserted in test_hardening.TestRateLimits. """ chal = identity.challenge(store, agent, limit=limit, window=window) sig = sign(private, chal["nonce"]) return identity.verify( store, chal["nonce"], sig, limit=limit, window=window )["token"] def issue(store, private, agent="bigpickle", **kw): """Mint a view code the way production does: authenticate, then ask. `limit`/`window` tune both the challenge quota and the code quota, since a test that mints many codes trips both. """ quota = {k: kw[k] for k in ("limit", "window") if k in kw} token = agent_token(store, private, agent, **quota) return viewcodes.issue_code(store, token, **kw) def fresh(agent="bigpickle"): store = Store(":memory:") private, _ = enrol(store, agent) return store, private