import json import subprocess from pathlib import Path SECURITY_CENTER = Path(__file__).parents[1] / "frontend" / "security-center.js" def test_source_branch_cleanup_has_a_specific_security_activity_label(): source = SECURITY_CENTER.read_text() assert "source_branch_deleted: 'Source branch deleted'" in source def test_release_rollback_has_a_specific_security_activity_label(): source = SECURITY_CENTER.read_text() assert "release_rollback_prepared: 'Release rollback prepared'" in source 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, action = json.loads(completed.stdout) assert title == "Passkey counter anomaly" assert "Remove and re-enroll this passkey" in detail assert action == "Review passkeys" def test_activity_alert_hands_off_to_addressable_devices_section(): harness = f""" const attachSecurityCenter=require({json.dumps(str(SECURITY_CENTER))}); const listeners={{}}; const element=(id='')=>({{ id, hidden:true, disabled:false, textContent:'', children:[], className:'', dataset:{{}}, attributes:{{}}, addEventListener(type,listener){{(this.listeners ||= {{}})[type]=listener;}}, click(){{this.listeners?.click?.({{preventDefault(){{}}}});}}, focus(){{}}, replaceChildren(){{this.children=[];}}, append(...values){{this.children.push(...values);}}, setAttribute(name,value){{this.attributes[name]=String(value);}}, removeAttribute(name){{delete this.attributes[name];}}, scrollIntoView(){{this.scrolled=true;}}, }}); const names=['active-devices','active-devices-sheet','active-devices-list','active-devices-status', 'enrolled-passkeys-list','enrolled-passkeys-status','enroll-passkey','security-activity-list', 'security-activity-status','load-more-security-activity','close-active-devices', 'security-section-activity','security-section-devices','security-section-passkeys', 'security-activity-section','security-devices-section','security-passkeys-section']; const ids=Object.fromEntries(names.map(id=>[id,element(id)])); const pushed=[]; const root={{ document:{{getElementById:id=>ids[id]||null,createElement:()=>element()}}, history:{{state:null,pushState(state,_title,url){{this.state=state;pushed.push({{state,url}});}}}}, location:{{pathname:'/dashboard/',search:'',hash:''}}, addEventListener:(type,listener)=>listeners[type]=listener, }}; const boundary={{ listActiveDevices:async()=>[], listPasskeys:async()=>[], listSecurityEvents:async()=>({{events:[],authentication_alerts:[{{}}],next_cursor:null}}), formatAuthenticationAlert:()=>({{title:'Failed sign-ins',detail:'Three attempts'}}), }}; (async()=>{{ const controller=attachSecurityCenter({{root,boundary}}); await controller.open(); const alert=ids['security-activity-list'].children[0]; const action=alert.children[2]; action.click(); console.log(JSON.stringify({{ initial:pushed[0], latest:pushed.at(-1), action:action.textContent, current:ids['security-section-devices'].attributes['aria-current'], scrolled:ids['security-devices-section'].scrolled||false, }})); }})().catch(error=>{{console.error(error);process.exit(1);}}); """ completed = subprocess.run( ["node", "-e", harness], check=True, capture_output=True, text=True ) output = json.loads(completed.stdout) assert output["initial"]["state"]["stackchainSecuritySection"] == "activity" assert output["initial"]["url"] == "/dashboard/#security/activity" assert output["latest"]["state"]["stackchainSecuritySection"] == "devices" assert output["action"] == "Review devices" assert output["current"] == "page" assert output["scrolled"] is True def test_device_revocation_refreshes_inventory_and_activity_for_verification(): harness = f""" const attachSecurityCenter=require({json.dumps(str(SECURITY_CENTER))}); const element=()=>({{ hidden:true, disabled:false, textContent:'', children:[], className:'', attributes:{{}}, addEventListener(type,listener){{(this.listeners ||= {{}})[type]=listener;}}, click(){{return this.listeners?.click?.();}}, focus(){{}}, replaceChildren(){{this.children=[];}}, append(...values){{this.children.push(...values);}}, setAttribute(name,value){{this.attributes[name]=value;}}, removeAttribute(name){{delete this.attributes[name];}}, scrollIntoView(){{}}, }}); const names=['active-devices','active-devices-sheet','active-devices-list','active-devices-status', 'enrolled-passkeys-list','enrolled-passkeys-status','enroll-passkey','security-activity-list', 'security-activity-status','load-more-security-activity','close-active-devices']; const ids=Object.fromEntries(names.map(id=>[id,element()])); const calls={{devices:0,activity:0,revoke:0}}; const root={{document:{{getElementById:id=>ids[id]||null,createElement:()=>element()}}}}; const boundary={{ listActiveDevices:async()=>{{calls.devices++;return [{{device_label:'Lost phone',created_at:1,expires_at:2,current:false}}];}}, listPasskeys:async()=>[], listSecurityEvents:async()=>{{calls.activity++;return {{events:[],authentication_alerts:[],next_cursor:null}};}}, revokeActiveDevice:async()=>{{calls.revoke++;return true;}}, }}; (async()=>{{ await attachSecurityCenter({{root,boundary}}).open(); await ids['active-devices-list'].children[0].children[1].click(); console.log(JSON.stringify({{calls,status:ids['security-activity-status'].textContent}})); }})().catch(error=>{{console.error(error);process.exit(1);}}); """ completed = subprocess.run( ["node", "-e", harness], check=True, capture_output=True, text=True ) output = json.loads(completed.stdout) assert output["calls"] == {"devices": 2, "activity": 2, "revoke": 1} assert output["status"] == "No security activity yet." def test_back_unwinds_security_sections_then_closes_and_restores_focus(): harness = f""" const attachSecurityCenter=require({json.dumps(str(SECURITY_CENTER))}); const listeners={{}}; const element=()=>({{ hidden:true, textContent:'', children:[], attributes:{{}}, addEventListener(type,listener){{(this.listeners ||= {{}})[type]=listener;}}, focus(){{this.focused=true;}}, replaceChildren(){{this.children=[];}}, append(...values){{this.children.push(...values);}}, setAttribute(name,value){{this.attributes[name]=value;}}, removeAttribute(name){{delete this.attributes[name];}}, scrollIntoView(){{}}, }}); const names=['active-devices','active-devices-sheet','active-devices-list','active-devices-status', 'enrolled-passkeys-list','enrolled-passkeys-status','enroll-passkey','security-activity-list', 'security-activity-status','load-more-security-activity','close-active-devices', 'security-section-activity','security-section-devices','security-section-passkeys', 'security-activity-section','security-devices-section','security-passkeys-section']; const ids=Object.fromEntries(names.map(id=>[id,element()])); const pushed=[]; const root={{ document:{{getElementById:id=>ids[id]||null,createElement:()=>element()}}, history:{{state:null,pushState(state,_title,url){{this.state=state;pushed.push(url);}}}}, location:{{pathname:'/dashboard/',search:''}}, addEventListener:(type,listener)=>listeners[type]=listener, }}; const boundary={{ listActiveDevices:async()=>[],listPasskeys:async()=>[], listSecurityEvents:async()=>({{events:[],authentication_alerts:[],next_cursor:null}}), }}; (async()=>{{ const controller=attachSecurityCenter({{root,boundary}}); await controller.open(); controller.navigate('devices'); listeners.popstate({{state:{{stackchainSecuritySection:'activity'}}}}); const afterFirst={{hidden:ids['active-devices-sheet'].hidden,current:ids['security-section-activity'].attributes['aria-current']}}; listeners.popstate({{state:null}}); console.log(JSON.stringify({{afterFirst,hidden:ids['active-devices-sheet'].hidden,focused:ids['active-devices'].focused||false,pushed}})); }})().catch(error=>{{console.error(error);process.exit(1);}}); """ completed = subprocess.run( ["node", "-e", harness], check=True, capture_output=True, text=True ) output = json.loads(completed.stdout) assert output["afterFirst"] == {"hidden": False, "current": "page"} assert output["hidden"] is True assert output["focused"] is True assert output["pushed"] == ["/dashboard/#security/activity", "/dashboard/#security/devices"] def test_security_center_finishes_its_today_detour_only_when_the_sheet_closes(): harness = f""" const attachSecurityCenter=require({json.dumps(str(SECURITY_CENTER))}); const listeners={{}}; const element=()=>({{ hidden:true,textContent:'',children:[],attributes:{{}}, addEventListener(){{}},focus(){{}},replaceChildren(){{this.children=[];}},append(...values){{this.children.push(...values);}}, setAttribute(name,value){{this.attributes[name]=value;}},removeAttribute(name){{delete this.attributes[name];}},scrollIntoView(){{}}, }}); const names=['active-devices','active-devices-sheet','active-devices-list','active-devices-status', 'enrolled-passkeys-list','enrolled-passkeys-status','enroll-passkey','security-activity-list', 'security-activity-status','load-more-security-activity','close-active-devices', 'security-section-activity','security-section-devices','security-section-passkeys', 'security-activity-section','security-devices-section','security-passkeys-section']; const ids=Object.fromEntries(names.map(id=>[id,element()])); const root={{ document:{{getElementById:id=>ids[id]||null,createElement:()=>element()}}, history:{{state:null,pushState(state){{this.state=state;}}}}, location:{{pathname:'/dashboard/',search:''}}, addEventListener:(type,listener)=>listeners[type]=listener, }}; const boundary={{listActiveDevices:async()=>[],listPasskeys:async()=>[],listSecurityEvents:async()=>({{events:[],authentication_alerts:[],next_cursor:null}})}}; let closes=0; (async()=>{{ const controller=attachSecurityCenter({{root,boundary,onClose:()=>closes++}}); await controller.open(); listeners.popstate({{state:{{stackchainSecuritySection:'devices'}}}}); const afterSectionBack=closes; listeners.popstate({{state:null}}); listeners.popstate({{state:null}}); console.log(JSON.stringify({{afterSectionBack,closes,hidden:ids['active-devices-sheet'].hidden}})); }})().catch(error=>{{console.error(error);process.exit(1);}}); """ completed = subprocess.run(["node", "-e", harness], capture_output=True, text=True) assert completed.returncode == 0, completed.stderr assert json.loads(completed.stdout) == { "afterSectionBack": 0, "closes": 1, "hidden": True, } def test_close_uses_history_back_to_remove_security_center_route(): harness = f""" const attachSecurityCenter=require({json.dumps(str(SECURITY_CENTER))}); const element=()=>({{ hidden:true,textContent:'',children:[],attributes:{{}}, addEventListener(type,listener){{(this.listeners ||= {{}})[type]=listener;}}, click(){{return this.listeners?.click?.({{preventDefault(){{}}}});}},focus(){{}},replaceChildren(){{this.children=[];}}, append(...values){{this.children.push(...values);}},setAttribute(){{}},removeAttribute(){{}},scrollIntoView(){{}}, }}); const names=['active-devices','active-devices-sheet','active-devices-list','active-devices-status', 'enrolled-passkeys-list','enrolled-passkeys-status','enroll-passkey','security-activity-list', 'security-activity-status','load-more-security-activity','close-active-devices']; const ids=Object.fromEntries(names.map(id=>[id,element()])); let backs=0; const root={{ document:{{getElementById:id=>ids[id]||null,createElement:()=>element()}}, history:{{state:null,pushState(state){{this.state=state;}},back(){{backs++;}}}}, location:{{pathname:'/dashboard/',search:''}},addEventListener(){{}}, }}; const boundary={{listActiveDevices:async()=>[],listPasskeys:async()=>[],listSecurityEvents:async()=>({{events:[],authentication_alerts:[],next_cursor:null}})}}; (async()=>{{ await attachSecurityCenter({{root,boundary}}).open(); ids['close-active-devices'].click(); console.log(JSON.stringify({{backs}})); }})().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) == {"backs": 1} def test_security_center_contains_focus_and_restores_prior_background_state_on_final_back(): harness = f""" const attachSecurityCenter=require({json.dumps(str(SECURITY_CENTER))}); const listeners={{}}; const element=(id='', inert=false)=>({{ id, inert, hidden:false, disabled:false, textContent:'', children:[], attributes:{{}}, addEventListener(type,listener){{(this.listeners ||= {{}})[type]=listener;}}, focus(){{focused=this;}}, replaceChildren(){{this.children=[];}}, append(...values){{this.children.push(...values);}}, setAttribute(name,value){{this.attributes[name]=value;}}, removeAttribute(name){{delete this.attributes[name];}}, scrollIntoView(){{}}, }}); let focused=null; const names=['active-devices','active-devices-sheet','active-devices-list','active-devices-status', 'enrolled-passkeys-list','enrolled-passkeys-status','enroll-passkey','security-activity-list', 'security-activity-status','load-more-security-activity','close-active-devices', 'security-section-activity','security-section-devices','security-section-passkeys', 'security-activity-section','security-devices-section','security-passkeys-section']; const ids=Object.fromEntries(names.map(id=>[id,element(id)])); ids['active-devices-sheet'].hidden=true; const header=element('header'); const main=element('main', true); const dock=element('mobile-task-dock'); const dynamicAction=element('revoke-lost-phone'); const hiddenAction=element('hidden-action'); hiddenAction.hidden=true; const disabledAction=element('disabled-action'); disabledAction.disabled=true; ids['active-devices-sheet'].querySelectorAll=()=>[ ids['close-active-devices'], dynamicAction, hiddenAction, disabledAction, ]; const documentListeners={{}}; const root={{ document:{{ getElementById:id=>ids[id]||null, createElement:()=>element(), querySelector:selector=>({{'header':header,'main':main,'#mobile-task-dock':dock}})[selector]||null, addEventListener:(type,listener)=>documentListeners[type]=listener, }}, history:{{state:null,pushState(state){{this.state=state;}}}}, location:{{pathname:'/dashboard/',search:''}}, addEventListener:(type,listener)=>listeners[type]=listener, }}; const boundary={{listActiveDevices:async()=>[],listPasskeys:async()=>[],listSecurityEvents:async()=>({{events:[],authentication_alerts:[],next_cursor:null}})}}; (async()=>{{ const controller=attachSecurityCenter({{root,boundary}}); await controller.open(); const opened={{inert:[header.inert,main.inert,dock.inert],focused:focused?.id}}; let shiftPrevented=false; documentListeners.keydown({{key:'Tab',shiftKey:true,target:ids['close-active-devices'],preventDefault(){{shiftPrevented=true;}}}}); const afterShift=focused?.id; let tabPrevented=false; documentListeners.keydown({{key:'Tab',shiftKey:false,target:dynamicAction,preventDefault(){{tabPrevented=true;}}}}); const afterTab=focused?.id; controller.navigate('devices'); header.inert=false; // An earlier popstate listener released its own overlay background. listeners.popstate({{state:{{stackchainSecuritySection:'activity'}}}}); header.inert=false; // That listener also reacts to the resulting hashchange. root.history.state={{stackchainSecuritySection:'activity'}}; listeners.hashchange({{}}); const sectionBack={{hidden:ids['active-devices-sheet'].hidden,inert:[header.inert,main.inert,dock.inert]}}; root.history.state=null; listeners.popstate({{state:null}}); console.log(JSON.stringify({{ opened,shiftPrevented,afterShift,tabPrevented,afterTab,sectionBack, closed:{{hidden:ids['active-devices-sheet'].hidden,inert:[header.inert,main.inert,dock.inert],focused:focused?.id}}, }})); }})().catch(error=>{{console.error(error);process.exit(1);}}); """ completed = subprocess.run( ["node", "-e", harness], capture_output=True, text=True ) assert completed.returncode == 0, completed.stderr assert json.loads(completed.stdout) == { "opened": {"inert": [True, True, True], "focused": "close-active-devices"}, "shiftPrevented": True, "afterShift": "revoke-lost-phone", "tabPrevented": True, "afterTab": "close-active-devices", "sectionBack": {"hidden": False, "inert": [True, True, True]}, "closed": { "hidden": True, "inert": [False, True, False], "focused": "active-devices", }, } def test_escape_closes_security_center_through_history_and_releases_background(): harness = f""" const attachSecurityCenter=require({json.dumps(str(SECURITY_CENTER))}); const windowListeners={{}}; const documentListeners={{}}; const element=(id='')=>({{ id,inert:false,hidden:false,disabled:false,textContent:'',children:[],attributes:{{}}, addEventListener(){{}},focus(){{focused=this.id;}},replaceChildren(){{this.children=[];}}, append(...values){{this.children.push(...values);}},setAttribute(){{}},removeAttribute(){{}},scrollIntoView(){{}}, }}); let focused=''; const names=['active-devices','active-devices-sheet','active-devices-list','active-devices-status', 'enrolled-passkeys-list','enrolled-passkeys-status','enroll-passkey','security-activity-list', 'security-activity-status','load-more-security-activity','close-active-devices']; const ids=Object.fromEntries(names.map(id=>[id,element(id)])); ids['active-devices-sheet'].hidden=true; ids['active-devices-sheet'].querySelectorAll=()=>[ids['close-active-devices']]; const header=element('header'); let backs=0; const root={{ document:{{ getElementById:id=>ids[id]||null,createElement:()=>element(), querySelector:selector=>selector==='header'?header:null, addEventListener:(type,listener)=>documentListeners[type]=listener, }}, history:{{state:null,pushState(state){{this.state=state;}},back(){{backs++;}}}}, location:{{pathname:'/dashboard/',search:''}}, addEventListener:(type,listener)=>windowListeners[type]=listener, }}; const boundary={{listActiveDevices:async()=>[],listPasskeys:async()=>[],listSecurityEvents:async()=>({{events:[],authentication_alerts:[],next_cursor:null}})}}; (async()=>{{ await attachSecurityCenter({{root,boundary}}).open(); let prevented=false; documentListeners.keydown({{key:'Escape',preventDefault(){{prevented=true;}}}}); const requested={{backs,prevented,hidden:ids['active-devices-sheet'].hidden,inert:header.inert}}; windowListeners.popstate({{state:null}}); console.log(JSON.stringify({{requested,closed:{{hidden:ids['active-devices-sheet'].hidden,inert:header.inert,focused}}}})); }})().catch(error=>{{console.error(error);process.exit(1);}}); """ completed = subprocess.run( ["node", "-e", harness], capture_output=True, text=True ) assert completed.returncode == 0, completed.stderr assert json.loads(completed.stdout) == { "requested": {"backs": 1, "prevented": True, "hidden": False, "inert": True}, "closed": {"hidden": True, "inert": False, "focused": "active-devices"}, }