66 lines
3.4 KiB
Python
66 lines
3.4 KiB
Python
"""Browser branch execution in disposable user/mount/network namespaces.
|
|
|
|
No host X socket, profile, service bus, device, or application data is exposed.
|
|
"""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
class BrowserTests(unittest.TestCase):
|
|
def run_browser(self, missing=None, socket_present=True):
|
|
with tempfile.TemporaryDirectory(prefix='c01-kiosk-test-') as directory:
|
|
work = Path(directory)
|
|
(work / 'chromium').write_text('#!/usr/bin/python3\nimport json,os,sys\nprint(json.dumps({"args":sys.argv[1:],"display":os.environ["DISPLAY"],"home":os.environ["HOME"],"runtime":os.environ["XDG_RUNTIME_DIR"],"uid":os.getuid(),"groups":os.getgroups()}))\n')
|
|
(work / 'chromium').chmod(0o755)
|
|
(work / 'driver.py').write_text('''import os,socket,subprocess,sys
|
|
os.makedirs('/tmp/.X11-unix')
|
|
os.makedirs('/var/lib/archipelago/chromium-kiosk')
|
|
s=socket.socket(socket.AF_UNIX)
|
|
if sys.argv[1]=='yes':s.bind('/tmp/.X11-unix/X0')
|
|
os.environ.update(PATH='/test:/usr/bin',KIOSK_WIN_W='1280',KIOSK_WIN_H='720',KIOSK_SCALE='1.50',ENABLE_FEATURES='OverlayScrollbar,VaapiVideoDecodeLinuxGL',ARCHIPELAGO_UID='1000',GPU_FLAGS='--in-process-gpu',EXTRA_DISABLED_FEATURES='',KIOSK_SAFE_AREA_X_PX='32',KIOSK_SAFE_AREA_Y_PX='24')
|
|
if sys.argv[2]!='none':os.environ.pop(sys.argv[2])
|
|
r=subprocess.run(['/usr/bin/bash','/launcher','--c01-browser'])
|
|
sys.exit(r.returncode)
|
|
''')
|
|
return subprocess.run(['bwrap','--unshare-all','--die-with-parent','--new-session',
|
|
'--uid','1000','--gid','1000','--ro-bind','/usr','/usr','--symlink','usr/bin','/bin',
|
|
'--symlink','usr/lib','/lib','--symlink','usr/lib64','/lib64',
|
|
'--proc','/proc','--dev','/dev','--tmpfs','/tmp','--tmpfs','/var',
|
|
'--ro-bind',str(work),'/test','--ro-bind',str(ROOT/'image-recipe/configs/archipelago-kiosk-launcher.sh'),'/launcher',
|
|
'/usr/bin/python3','/test/driver.py','yes' if socket_present else 'no',missing or 'none'],
|
|
capture_output=True,text=True,timeout=20)
|
|
|
|
def test_preserves_browser_profile_display_audio_and_cdp_arguments(self):
|
|
result = self.run_browser()
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
data = json.loads(result.stdout)
|
|
self.assertEqual(data['uid'], 1000)
|
|
self.assertEqual(data['display'], ':0')
|
|
self.assertEqual(data['home'], '/home/archipelago')
|
|
self.assertEqual(data['runtime'], '/run/user/1000')
|
|
for argument in ('--user-data-dir=/var/lib/archipelago/chromium-kiosk',
|
|
'--remote-debugging-port=9222','--window-size=1280,720',
|
|
'--force-device-scale-factor=1.50','--in-process-gpu',
|
|
'--app=http://localhost/kiosk?safe_area_x=32&safe_area_y=24'):
|
|
self.assertIn(argument, data['args'])
|
|
|
|
def test_waits_for_display_without_starting_browser(self):
|
|
result = self.run_browser(socket_present=False)
|
|
self.assertEqual(result.returncode, 75, result.stderr)
|
|
self.assertEqual(result.stdout, '')
|
|
|
|
def test_missing_display_owner_environment_refuses_browser(self):
|
|
result = self.run_browser(missing='KIOSK_SCALE')
|
|
self.assertEqual(result.returncode, 75, result.stderr)
|
|
self.assertEqual(result.stdout, '')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|