57 lines
2.0 KiB
Python
57 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
import pytest
|
|
|
|
from yovision_brain.integration.event_export import SQLiteReplayCache
|
|
from yovision_brain.integration.machine_identity import (
|
|
KeyRecord,
|
|
MachineIdentityError,
|
|
Registry,
|
|
Signer,
|
|
Verifier,
|
|
)
|
|
|
|
|
|
def test_replay_cache_rejects_same_jti_after_connector_restart(tmp_path) -> None:
|
|
now = 1_800_000_000
|
|
private_key = Ed25519PrivateKey.generate()
|
|
registry = Registry(
|
|
[
|
|
KeyRecord(
|
|
principal="yv:brain:node-a",
|
|
key_id="brain-key-0001",
|
|
public_key=private_key.public_key(),
|
|
audience="yovision-sense",
|
|
scopes=frozenset({"events:ingest"}),
|
|
)
|
|
]
|
|
)
|
|
token = Signer(
|
|
"yv:brain:node-a",
|
|
"brain-key-0001",
|
|
private_key,
|
|
clock=lambda: now,
|
|
).mint("yovision-sense", ["events:ingest"], "POST", "/v1/events", b"{}")
|
|
database = tmp_path / "machine-replay.sqlite3"
|
|
|
|
first_process = Verifier(registry, SQLiteReplayCache(database), clock=lambda: now)
|
|
claims = first_process.verify(
|
|
token, "yovision-sense", "events:ingest", "POST", "/v1/events", b"{}"
|
|
)
|
|
assert claims.iss == "yv:brain:node-a"
|
|
|
|
restarted_process = Verifier(registry, SQLiteReplayCache(database), clock=lambda: now)
|
|
with pytest.raises(MachineIdentityError, match="machine_token_replayed") as caught:
|
|
restarted_process.verify(
|
|
token, "yovision-sense", "events:ingest", "POST", "/v1/events", b"{}"
|
|
)
|
|
assert caught.value.code == "machine_token_replayed"
|
|
|
|
|
|
def test_replay_cache_atomically_reuses_expired_identity(tmp_path) -> None:
|
|
cache = SQLiteReplayCache(tmp_path / "machine-replay.sqlite3")
|
|
assert cache.consume("yv:brain:node-a", "jti-one", expires_at=110, now=100)
|
|
assert not cache.consume("yv:brain:node-a", "jti-one", expires_at=110, now=101)
|
|
assert cache.consume("yv:brain:node-a", "jti-one", expires_at=130, now=110)
|