stackchain-dashboard/tests/test_live_snapshot_store.py
timmy 9d9b28af8e
All checks were successful
CI / lint (pull_request) Successful in 2m48s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Successful in 2m55s
CI / release-candidate (pull_request) Has been skipped
security: encrypt worker-shared snapshots (Closes #1106)
2026-08-19 01:58:22 +00:00

247 lines
9.3 KiB
Python

import threading
import os
import sqlite3
import pytest
from src import live_snapshot_store
from src.live_snapshot_store import LiveSnapshotStore, RefreshLeaseLost
from src.state_encryption import PrivateStateEncryptionError
PRIVATE_KEY = b"l" * 32
def test_published_live_snapshot_is_encrypted_at_rest_and_survives_restart(tmp_path):
path = tmp_path / "live.sqlite3"
store = LiveSnapshotStore(path, clock=lambda: 100.0, encryption_key=PRIVATE_KEY)
lease = store.try_acquire_refresh({"context"}, lease_seconds=5)
canary = "private-live-title-canary"
published = store.publish_refresh(
lease,
value={"context": {"title": canary}, "events": [], "notifications": []},
created_at={section: 100.0 for section in live_snapshot_store.SECTIONS},
failure_count={section: 0 for section in live_snapshot_store.SECTIONS},
retry_at={section: None for section in live_snapshot_store.SECTIONS},
changed_sections={"context"},
)
with sqlite3.connect(path) as connection:
payload = connection.execute(
"SELECT value_json FROM live_snapshot WHERE singleton = 1"
).fetchone()[0]
assert payload.startswith("v1:")
assert canary not in payload
assert LiveSnapshotStore(path, clock=lambda: 100.0, encryption_key=PRIVATE_KEY).load().value == published.value
def test_live_snapshot_lazily_migrates_plaintext_without_changing_metadata(tmp_path):
path = tmp_path / "live.sqlite3"
store = LiveSnapshotStore(path, clock=lambda: 100.0, encryption_key=PRIVATE_KEY)
legacy = {"context": {"title": "legacy"}, "events": [], "notifications": []}
with sqlite3.connect(path) as connection:
connection.execute(
"UPDATE live_snapshot SET value_json = ?, revisions_json = ? WHERE singleton = 1",
('{"context":{"title":"legacy"},"events":[],"notifications":[]}',
'{"context":4,"events":2,"notifications":1}'),
)
state = store.load()
with sqlite3.connect(path) as connection:
migrated = connection.execute(
"SELECT value_json FROM live_snapshot WHERE singleton = 1"
).fetchone()[0]
assert state.value == legacy
assert state.revisions == {"context": 4, "events": 2, "notifications": 1}
assert migrated.startswith("v1:")
def test_live_snapshot_authentication_failure_returns_no_private_content(tmp_path):
path = tmp_path / "live.sqlite3"
store = LiveSnapshotStore(path, clock=lambda: 100.0, encryption_key=PRIVATE_KEY)
lease = store.try_acquire_refresh({"context"}, lease_seconds=5)
metadata = {section: None for section in live_snapshot_store.SECTIONS}
store.publish_refresh(
lease,
value={"context": {"title": "secret"}},
created_at=metadata,
failure_count={section: 0 for section in metadata},
retry_at=metadata,
changed_sections={"context"},
)
with pytest.raises(PrivateStateEncryptionError, match="private state could not be decrypted"):
LiveSnapshotStore(path, encryption_key=b"x" * 32).load()
def test_metadata_load_does_not_retrieve_or_decode_snapshot_value(tmp_path):
store = LiveSnapshotStore(tmp_path / "live.sqlite3", clock=lambda: 100.0)
with sqlite3.connect(store.path) as connection:
connection.execute(
"UPDATE live_snapshot SET value_json = ? WHERE singleton = 1",
("not-json",),
)
metadata = store.load_metadata()
assert metadata.created_at == {
section: None for section in ("context", "events", "notifications")
}
assert metadata.revisions == {
section: 0 for section in ("context", "events", "notifications")
}
with pytest.raises(PrivateStateEncryptionError):
store.load()
def test_independent_stores_racing_for_refresh_have_one_lease_winner(tmp_path):
path = tmp_path / "live.sqlite3"
first = LiveSnapshotStore(path, clock=lambda: 100.0)
second = LiveSnapshotStore(path, clock=lambda: 100.0)
barrier = threading.Barrier(2)
results = []
def acquire(store):
barrier.wait()
results.append(store.try_acquire_refresh({"context", "events"}, lease_seconds=5))
threads = [threading.Thread(target=acquire, args=(store,)) for store in (first, second)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
assert sum(result is not None for result in results) == 1
def test_snapshot_and_shared_revisions_publish_atomically(tmp_path):
path = tmp_path / "live.sqlite3"
writer = LiveSnapshotStore(path, clock=lambda: 100.0)
reader = LiveSnapshotStore(path, clock=lambda: 100.0)
lease = writer.try_acquire_refresh(set(("context", "events", "notifications")), lease_seconds=5)
assert lease is not None
state = writer.publish_refresh(
lease,
value={
"context": {"generation": 1},
"events": [],
"notifications": [],
"sections": {section: "fresh" for section in ("context", "events", "notifications")},
},
created_at={section: 100.0 for section in ("context", "events", "notifications")},
failure_count={section: 0 for section in ("context", "events", "notifications")},
retry_at={section: None for section in ("context", "events", "notifications")},
changed_sections=set(("context", "events", "notifications")),
)
observed = reader.load()
assert observed.value == state.value
assert observed.revisions == {"context": 1, "events": 1, "notifications": 1}
assert observed.refreshing_sections == set()
with pytest.raises(RefreshLeaseLost):
writer.publish_refresh(
lease,
value={"context": {"generation": 2}},
created_at=observed.created_at,
failure_count=observed.failure_count,
retry_at=observed.retry_at,
changed_sections={"context"},
)
def test_expired_refresh_lease_can_be_recovered(tmp_path):
now = 100.0
path = tmp_path / "live.sqlite3"
abandoned = LiveSnapshotStore(path, clock=lambda: now)
recovery = LiveSnapshotStore(path, clock=lambda: now)
first = abandoned.try_acquire_refresh({"context"}, lease_seconds=5)
assert first is not None
assert recovery.try_acquire_refresh({"context"}, lease_seconds=5) is None
now = 106.0
second = recovery.try_acquire_refresh({"context"}, lease_seconds=5)
assert second is not None
assert second != first
def test_default_store_clock_uses_reboot_stable_wall_time(tmp_path, monkeypatch):
epoch = 1_700_000_000.0
monkeypatch.setattr(live_snapshot_store.time, "time", lambda: epoch)
store = LiveSnapshotStore(tmp_path / "live.sqlite3")
lease = store.try_acquire_refresh({"context"}, lease_seconds=5)
assert lease is not None
assert store.load().lease_expires_at == epoch + 5
def test_store_is_private_and_does_not_persist_upstream_token(tmp_path, monkeypatch):
token = "gitea-super-secret-token-material"
monkeypatch.setenv("GITEA_TOKEN", token)
path = tmp_path / "private-state" / "live.sqlite3"
LiveSnapshotStore(path)
assert os.stat(path).st_mode & 0o777 == 0o600
assert os.stat(path.parent).st_mode & 0o777 == 0o700
assert token.encode() not in path.read_bytes()
def test_remove_notifications_filters_batch_with_one_revision_advance(tmp_path):
store = LiveSnapshotStore(tmp_path / "live.sqlite3", clock=lambda: 100.0)
lease = store.try_acquire_refresh({"notifications"}, lease_seconds=5)
assert lease is not None
metadata = {section: None for section in ("context", "events", "notifications")}
published = store.publish_refresh(
lease,
value={
"notifications": [{"id": 7}, {"id": 8}, {"id": 9}],
"sections": {"notifications": "fresh"},
},
created_at=metadata,
failure_count={section: 0 for section in metadata},
retry_at=metadata,
changed_sections={"notifications"},
)
removed = store.remove_notifications([7, 9, 7])
assert removed.value["notifications"] == [{"id": 8}]
assert removed.revisions["notifications"] == published.revisions["notifications"] + 1
def test_read_notification_filter_is_shared_with_future_publications(tmp_path):
path = tmp_path / "live.sqlite3"
first = LiveSnapshotStore(path, clock=lambda: 100.0)
second = LiveSnapshotStore(path, clock=lambda: 100.0)
lease = first.try_acquire_refresh({"notifications"}, lease_seconds=5)
assert lease is not None
metadata = {section: None for section in ("context", "events", "notifications")}
first.publish_refresh(
lease,
value={"notifications": [{"id": 7}, {"id": 8}], "sections": {"notifications": "fresh"}},
created_at=metadata,
failure_count={section: 0 for section in metadata},
retry_at=metadata,
changed_sections={"notifications"},
)
removed = second.remove_notification(7)
lease = first.try_acquire_refresh({"notifications"}, lease_seconds=5)
assert lease is not None
republished = first.publish_refresh(
lease,
value={"notifications": [{"id": 7}, {"id": 8}], "sections": {"notifications": "fresh"}},
created_at=metadata,
failure_count={section: 0 for section in metadata},
retry_at=metadata,
changed_sections={"notifications"},
)
assert removed.value["notifications"] == [{"id": 8}]
assert republished.value["notifications"] == [{"id": 8}]