stackchain-dashboard/tests/test_security_center.py
timmy c91194c283
All checks were successful
CI / lint (pull_request) Successful in 1m34s
CI / build-release (pull_request) Successful in 6s
CI / release-candidate (pull_request) Has been skipped
fix: detect atomic passkey counter anomalies (Closes #641)
2026-08-12 10:26:51 +00:00

89 lines
3.7 KiB
Python

import json
import subprocess
from pathlib import Path
SECURITY_CENTER = Path(__file__).parents[1] / "frontend" / "security-center.js"
def test_open_security_center_loads_all_sections_concurrently_and_is_awaitable():
harness = f"""
const attachSecurityCenter=require({json.dumps(str(SECURITY_CENTER))});
const calls=[];
const element=()=>({{
hidden:true, disabled:false, textContent:'', children:[],
addEventListener(){{}}, focus(){{this.focused=true;}},
replaceChildren(){{this.children=[];}}, append(value){{this.children.push(value);}},
}});
const ids={{
'active-devices':element(), 'active-devices-sheet':element(),
'active-devices-list':element(), 'active-devices-status':element(),
'enrolled-passkeys-list':element(), 'enrolled-passkeys-status':element(),
'enroll-passkey':element(), 'security-activity-list':element(),
'security-activity-status':element(), 'load-more-security-activity':element(),
'close-active-devices':element(),
}};
const root={{document:{{getElementById:id=>ids[id]||null,createElement:()=>element()}}}};
const boundary={{
listActiveDevices:async()=>{{calls.push('devices');return[];}},
listPasskeys:async()=>{{calls.push('passkeys');return[];}},
listSecurityEvents:async()=>{{calls.push('activity');return{{events:[],authentication_alerts:[],next_cursor:null}};}},
}};
(async()=>{{
const controller=attachSecurityCenter({{root,boundary}});
const loading=controller.open();
const awaitable=Boolean(loading&&typeof loading.then==='function');
if (loading) await loading;
console.log(JSON.stringify({{calls,awaitable,hidden:ids['active-devices-sheet'].hidden,focused:ids['close-active-devices'].focused||false}}));
}})().catch(error=>{{console.error(error);process.exit(1);}});
"""
completed = subprocess.run(
["node", "-e", harness], check=True, capture_output=True, text=True
)
assert json.loads(completed.stdout) == {
"calls": ["devices", "passkeys", "activity"],
"awaitable": True,
"hidden": False,
"focused": True,
}
def test_counter_anomaly_activity_gives_passkey_remediation_guidance():
harness = f"""
const attachSecurityCenter=require({json.dumps(str(SECURITY_CENTER))});
const element=()=>({{
hidden:true, disabled:false, textContent:'', children:[], className:'',
addEventListener(){{}}, focus(){{}}, replaceChildren(){{this.children=[];}},
append(...values){{this.children.push(...values);}},
}});
const ids={{
'active-devices':element(), 'active-devices-sheet':element(),
'active-devices-list':element(), 'active-devices-status':element(),
'enrolled-passkeys-list':element(), 'enrolled-passkeys-status':element(),
'enroll-passkey':element(), 'security-activity-list':element(),
'security-activity-status':element(), 'load-more-security-activity':element(),
'close-active-devices':element(),
}};
const root={{document:{{getElementById:id=>ids[id]||null,createElement:()=>element()}}}};
const boundary={{
listActiveDevices:async()=>[], listPasskeys:async()=>[],
listSecurityEvents:async()=>({{events:[{{
kind:'passkey_counter_anomaly', device_label:'Phone', method:'passkey',
target:'sign_in:dashboard', status:'completed', created_at:1,
}}],authentication_alerts:[],next_cursor:null}}),
}};
(async()=>{{
await attachSecurityCenter({{root,boundary}}).open();
const row=ids['security-activity-list'].children[0];
console.log(JSON.stringify(row.children.map(child=>child.textContent)));
}})().catch(error=>{{console.error(error);process.exit(1);}});
"""
completed = subprocess.run(
["node", "-e", harness], check=True, capture_output=True, text=True
)
title, detail = json.loads(completed.stdout)
assert title == "Passkey counter anomaly"
assert "Remove and re-enroll this passkey" in detail