Dotfiles_ArchAP/tests/overview/test_privacy.py

100 lines
5.6 KiB
Python

"""Synthetic cache/IPC only: never inspect or capture personal windows."""
import importlib.util
import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
from unittest.mock import patch
spec=importlib.util.spec_from_file_location('overview_privacy',Path(__file__).resolve().parents[2]/'quickshell/.config/quickshell/labfy-sway/overview/backend.py')
b=importlib.util.module_from_spec(spec);spec.loader.exec_module(b)
class Privacy(unittest.TestCase):
def setUp(self):
self.temp=tempfile.TemporaryDirectory();self.addCleanup(self.temp.cleanup)
self.root=Path(self.temp.name)
e=patch.dict(os.environ,XDG_RUNTIME_DIR=self.temp.name,XDG_CONFIG_HOME=self.temp.name)
e.start();self.addCleanup(e.stop)
old=os.umask(0o077);self.addCleanup(os.umask,old)
self.window={'id':42,'app':'TEST_ONLY','foreignId':'b'*32}
self.model={'cards':[{'number':1,'windows':[self.window]}]}
def write_policy(self,value):
p=self.root/'labfy-sway/overview-capture.json';p.parent.mkdir(exist_ok=True)
p.write_text(json.dumps(value))
def test_no_capture_when_closed(self):
with patch.object(b,'overview_open',return_value=False),patch.object(b.subprocess,'run',side_effect=AssertionError('capture while closed')):
self.assertEqual(b.capture_windows({1})['captured'],[])
def test_disabled_policy_and_exclusions_do_not_reach_grim(self):
for rules in [{'enabled':False},{'excludeApps':['TEST_*']}]:
self.write_policy(rules)
with patch.object(b,'overview_open',return_value=True),patch.object(b,'state',return_value=self.model),patch.object(b.subprocess,'run',side_effect=AssertionError('excluded capture')):
self.assertEqual(b.capture_windows({1})['captured'],[])
def test_invalid_policy_fails_closed(self):
self.write_policy({'enabled':'yes'})
self.assertFalse(b.policy()['enabled'])
p=self.root/'labfy-sway/overview-capture.json';p.unlink();p.symlink_to('/dev/zero')
self.assertFalse(b.policy()['enabled'])
def test_directory_symlink_and_insecure_mode_rejected(self):
outside=self.root/'outside';outside.mkdir();target=self.root/'labfy-workspace-overview'
target.symlink_to(outside,target_is_directory=True)
with self.assertRaises(OSError):b.cache_dir()
target.unlink();target.mkdir(mode=0o755);target.chmod(0o755)
with self.assertRaises(RuntimeError):b.cache_dir()
self.assertEqual(target.stat().st_mode&0o777,0o755)
def test_symlink_manifest_and_image_never_followed(self):
sentinel=self.root/'sentinel';sentinel.write_bytes(b'KEEP')
b.window_preview_path(42).symlink_to(sentinel)
self.assertIsNone(b.valid_window_preview(42,'b'*32))
b.purge()
self.assertEqual(sentinel.read_bytes(),b'KEEP')
def test_purge_does_not_touch_unrecognized_files(self):
c=b.cache_dir();(c/'unrelated.txt').write_text('KEEP');(c/'window-1.jpg').write_bytes(b'JPEG')
b.purge();self.assertTrue((c/'unrelated.txt').exists());self.assertFalse((c/'window-1.jpg').exists())
def test_count_and_byte_quotas(self):
c=b.cache_dir()
for i in range(6):(c/f'window-{i}.jpg').write_bytes(b'x'*8)
with patch.object(b,'MAX_CACHE_FILES',4),patch.object(b,'MAX_CACHE_BYTES',16):b.enforce_quota()
files=list(c.glob('*.jpg'));self.assertLessEqual(len(files),4);self.assertLessEqual(sum(p.stat().st_size for p in files),16)
def test_lock_during_capture_rejects_pixels_and_reaps_temporary(self):
def grim(args,**kwargs):
Path(args[-1]).write_bytes(b'JPEG')
(self.root/'labfy-lock.capture-guard').write_text('active\n')
return subprocess.CompletedProcess(args,0)
with patch.object(b,'overview_open',return_value=True),patch.object(b,'state',return_value=self.model),patch.object(b.subprocess,'run',side_effect=grim):
self.assertEqual(b.capture_windows({1})['captured'],[])
self.assertFalse(list(b.cache_dir().glob('*.jpg')))
def test_capture_timeout_cleans_temporary(self):
with patch.object(b,'overview_open',return_value=True),patch.object(b,'state',return_value=self.model),patch.object(b.subprocess,'run',side_effect=subprocess.TimeoutExpired('grim',2)):
self.assertEqual(b.capture_windows({1})['captured'],[])
self.assertFalse(list(b.cache_dir().glob('tmp*')))
def test_policy_change_purges_excluded_cached_window(self):
rect={'x':0,'y':0,'width':100,'height':100}
node={'type':'workspace','id':1,'num':1,'nodes':[dict(type='con',id=42,app_id='TEST_ONLY',rect=rect)],'rect':rect}
data={'get_tree':node,'get_workspaces':[dict(id=1,num=1,output='HEADLESS-1')],'get_outputs':[]}
(b.cache_dir()/'window-42.jpg').write_bytes(b'JPEG')
self.write_policy({'excludeApps':['TEST_ONLY']})
with patch.object(b,'sway',side_effect=lambda kind:data[kind]):
row=b.state()['cards'][0]['windows'][0]
self.assertTrue(row['excluded']);self.assertEqual(row['preview'],'');self.assertFalse((b.cache_dir()/'window-42.jpg').exists())
def test_lock_epoch_invalidates_previous_preview(self):
p=b.window_preview_path(42);p.write_bytes(b'JPEG')
b.window_preview_metadata_path(42).write_text(json.dumps(dict(version=1,conId=42,foreignId='b'*32,lockRevision=[],capturedNs=1,imageMtimeNs=p.stat().st_mtime_ns)))
self.assertIsNotNone(b.valid_window_preview(42,'b'*32))
(self.root/'labfy-lock.capture-guard').write_text('released\n')
self.assertIsNone(b.valid_window_preview(42,'b'*32))
if __name__=='__main__':unittest.main()