fix: purge every private offline store (Closes #889)
CI / lint (pull_request) Successful in 1m47s
CI / build-release (pull_request) Successful in 5s
CI / browser-journey (pull_request) Successful in 54s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-15 11:48:54 +00:00
1 parent 2eea42859e
commit a60f2cfac3
10 files changed
+95 -18

No files matched your search

+1 -1
View File
@@ -300,7 +300,7 @@ def test_offline_shell_precaches_exact_runtime_without_superseded_page_modules()
assert f"BASE + '{build.runtime_name}'" in build.service_worker_source
for source in build.page_sources:
if source == "static/background-issue-sync.js":
if f"importScripts(BASE + '{source}')" in build.service_worker_source:
continue
assert f"BASE + '{source}'" not in build.service_worker_source
+2
View File
@@ -100,7 +100,9 @@ const controller = createLoginController({{
async def test_login_loads_private_data_purger_before_controller():
html = await login()
assert '<script src="static/private-data-registry.js"></script>' in html
assert '<script src="static/private-device-data.js"></script>' in html
assert html.index('static/private-data-registry.js') < html.index('static/private-device-data.js')
assert html.index('static/private-device-data.js') < html.index('static/login.js')
+43
View File
@@ -0,0 +1,43 @@
import json
import re
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
FRONTEND = ROOT / "frontend"
REGISTRY = FRONTEND / "private-data-registry.js"
def test_private_database_registry_covers_every_shipped_indexeddb_store():
harness = f"""
const databases = require({json.dumps(str(REGISTRY))});
process.stdout.write(JSON.stringify(databases));
"""
completed = subprocess.run(
["node", "-e", harness], text=True, capture_output=True, check=True
)
registered = set(json.loads(completed.stdout))
opened = set()
for path in FRONTEND.glob("*.js"):
source = path.read_text()
opened.update(re.findall(r"dbName\s*=\s*['\"](stackchain-[^'\"]+)['\"]", source))
opened.update(re.findall(r"createIndexedDbTransaction\([^\n]+['\"](stackchain-[^'\"]+)['\"]", source))
assert registered == opened
assert registered == {
"stackchain-background-outbox-v1",
"stackchain-offline-work-v2",
"stackchain-unfiled-captures-v1",
}
def test_every_private_data_purge_context_consumes_the_shared_registry():
for name in ("private-device-data.js", "session.js", "service-worker.js"):
source = (FRONTEND / name).read_text()
assert "stackchainPrivateDatabases" in source
assert not re.search(r"deletePrivateDatabase\(['\"]stackchain-", source)
html = (FRONTEND / "index.html").read_text()
assert html.index('static/private-data-registry.js') < html.index('static/session.js')
+11 -3
View File
@@ -6,6 +6,7 @@ import pytest
WORKER = Path(__file__).resolve().parents[1] / "frontend" / "service-worker.js"
PRIVATE_DATA_REGISTRY = WORKER.parent / "private-data-registry.js"
def run_worker_scenario(scenario: str) -> dict:
@@ -46,6 +47,7 @@ const context = {{
location: {{ href: 'https://forge.example/dashboard/service-worker.js', origin: 'https://forge.example' }},
__STACKCHAIN_NAVIGATION_TIMEOUT_MS: 15,
__STACKCHAIN_PUSH_ACTION_TIMEOUT_MS: 15,
stackchainPrivateDatabases: require({json.dumps(str(PRIVATE_DATA_REGISTRY))}),
__STACKCHAIN_SHARED_ATTACHMENT_STORE: {{
put: async (id, value) => {{ state.sharedRecords[id] = value; }},
get: async id => state.sharedRecords[id] || null,
@@ -316,7 +318,9 @@ def test_revoked_background_session_purges_worker_data_and_notifies_dashboard_cl
assert result["outcome"] == {"status": 401, "code": "session_revoked"}
assert result["state"]["outboxPurges"] == 1
assert result["state"]["deletedDatabases"] == [
"stackchain-unfiled-captures-v1"
"stackchain-background-outbox-v1",
"stackchain-offline-work-v2",
"stackchain-unfiled-captures-v1",
]
assert result["state"]["deleted"] == ["stackchain-dashboard-old"]
assert result["state"]["clientMessages"] == [
@@ -406,7 +410,9 @@ def test_device_purge_message_stops_worker_outbox_and_acknowledges_completion():
assert result["state"]["outboxPurges"] == 1
assert result["state"]["deletedDatabases"] == [
"stackchain-unfiled-captures-v1"
"stackchain-background-outbox-v1",
"stackchain-offline-work-v2",
"stackchain-unfiled-captures-v1",
]
assert result["replies"] == [{"ok": True}]
@@ -999,7 +1005,9 @@ def test_expired_offline_lease_purges_private_worker_data_and_refuses_cached_she
assert result["body"] == "Your Stackchain session expired. Reconnect and sign in."
assert result["state"]["outboxPurges"] == 1
assert result["state"]["deletedDatabases"] == [
"stackchain-unfiled-captures-v1"
"stackchain-background-outbox-v1",
"stackchain-offline-work-v2",
"stackchain-unfiled-captures-v1",
]
assert result["state"]["deleted"] == ["stackchain-dashboard-old"]
assert "private cached dashboard" not in result["body"]