Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a06ed7-828d-7ca0-a8d4-0c3e5a0c4102
38 lines
1.8 KiB
Python
38 lines
1.8 KiB
Python
"""Single-key invalidation guarantees needed by the platform rotation fence."""
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
import pytest
|
|
|
|
from api.config import settings
|
|
from api.services.repository_rename import (
|
|
RenamePreconditionFailed, RenameServiceUnavailable,
|
|
_sign_preflight, _verify_preflight_token,
|
|
)
|
|
|
|
|
|
def test_rotation_invalidates_predecessor_and_accepts_successor(monkeypatch):
|
|
payload = {'expires_at': (datetime.now(timezone.utc) + timedelta(minutes=15)).isoformat()}
|
|
monkeypatch.setattr(settings, 'repository_rename_preflight_secret', 'fixture-old-key')
|
|
predecessor = _sign_preflight(payload)
|
|
assert _verify_preflight_token(predecessor) == payload
|
|
monkeypatch.setattr(settings, 'repository_rename_preflight_secret', 'fixture-new-key')
|
|
with pytest.raises(RenamePreconditionFailed):
|
|
_verify_preflight_token(predecessor)
|
|
assert _verify_preflight_token(_sign_preflight(payload)) == payload
|
|
|
|
|
|
def test_tamper_expiry_and_no_key_fail_closed(monkeypatch):
|
|
monkeypatch.setattr(settings, 'repository_rename_preflight_secret', 'fixture-key')
|
|
future = {'expires_at': (datetime.now(timezone.utc) + timedelta(minutes=15)).isoformat()}
|
|
token = _sign_preflight(future)
|
|
encoded, signature = token.split('.')
|
|
with pytest.raises(RenamePreconditionFailed):
|
|
_verify_preflight_token(encoded + '.' + ('A' if signature[0] != 'A' else 'B') + signature[1:])
|
|
past = {'expires_at': (datetime.now(timezone.utc) - timedelta(seconds=1)).isoformat()}
|
|
with pytest.raises(RenamePreconditionFailed, match='expired'):
|
|
_verify_preflight_token(_sign_preflight(past))
|
|
monkeypatch.setattr(settings, 'repository_rename_preflight_secret', None)
|
|
with pytest.raises(RenameServiceUnavailable):
|
|
_sign_preflight(future)
|
|
with pytest.raises(RenameServiceUnavailable):
|
|
_verify_preflight_token(token)
|