Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,99 @@
# SPDX-License-Identifier: MPL-2.0
import hashlib
import importlib.util
import io
import json
from pathlib import Path
import subprocess
import tarfile
import tempfile
import unittest
from unittest.mock import patch
ROOT = Path(__file__).resolve().parents[1]
def load(name, path):
spec = importlib.util.spec_from_file_location(name, ROOT/path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
stage = load('stage_runtime', 'tools/stage-runtime.py')
export = load('export_runtime', 'droidian/export-runtime.py')
display = load('compositor_trial', 'droidian/compositor-trial.py')
class ReferenceTests(unittest.TestCase):
def test_snapshot_excludes_configuration_and_private_trees(self):
for path in ('/etc/shadow', '/home/droidian/.ssh/id_ed25519',
'/var/lib/NetworkManager/secret', '/usr/local/private', '/usr/../etc/shadow'):
self.assertFalse(export.allowed(path), path)
self.assertTrue(export.allowed('/usr/share/doc/phoc/copyright'))
def test_dependency_alternative_and_versioned_virtual_provider(self):
def package(version, depends='', provides=''):
return {'Version': version, 'Architecture': 'arm64', 'Depends': depends,
'Pre-Depends': '', 'Provides': provides}
packages = {'app': package('1', 'missing | interface (>= 2)'),
'old': package('1', provides='interface (= 1)'),
'new': package('3', provides='interface (= 3)')}
def compare(args, **kwargs):
self.assertEqual(args[:2], ['dpkg', '--compare-versions'])
self.assertEqual(args[3:], ['>=', '2'])
return subprocess.CompletedProcess(args, 0 if args[2] == '3' else 1)
with patch.object(export.subprocess, 'run', side_effect=compare):
self.assertEqual(set(export.closure(packages, ['app'])), {'app', 'new'})
def test_unresolved_dependency_is_not_silently_dropped(self):
with self.assertRaisesRegex(ValueError, 'No installed provider'):
export.closure({}, ['missing'])
def test_legacy_lib_files_share_the_runtime_loader_directory(self):
with tempfile.TemporaryDirectory() as temporary:
source = Path(temporary)/'source'; source.mkdir()
data = b'reference library'; name = 'lib/example.so'
with tarfile.open(source/'runtime.tar', 'w') as tar:
info = tarfile.TarInfo(name); info.size = len(data); info.mode = 0o6755
tar.addfile(info, io.BytesIO(data))
manifest = {'archiveSha256': hashlib.sha256((source/'runtime.tar').read_bytes()).hexdigest(),
'files': {'/'+name: {'sha256': hashlib.sha256(data).hexdigest()}},
'packages': {'example': {}}, 'missing': []}
(source/'manifest.json').write_text(json.dumps(manifest))
root = Path(temporary)/'root'; stage.stage(source, root)
self.assertTrue((root/'lib').is_symlink())
self.assertEqual((root/'lib/example.so').read_bytes(), data)
self.assertEqual((root/'lib/example.so').stat().st_mode & 0o6000, 0)
self.assertFalse((root/'etc/machine-id').exists())
def test_archive_paths_cannot_escape_root(self):
for path in ('/usr/bin/x', 'usr/../../etc/shadow', 'etc/shadow'):
with self.assertRaises(ValueError):
stage.destination(path)
def test_gaia_child_drops_all_process_capabilities(self):
path = ROOT/'droidian/session.py'
code = "import runpy; runpy.run_path("+repr(str(path))+")[\"drop_capabilities\"](); print(open('/proc/self/status').read())"
result = subprocess.check_output(['python3', '-c', code], text=True)
values = dict(line.split(':', 1) for line in result.splitlines() if ':' in line)
for key in ('CapInh', 'CapPrm', 'CapEff', 'CapAmb'):
self.assertEqual(int(values[key].strip(), 16), 0, key)
def test_display_restore_continues_after_stop_timeout(self):
calls = []
def command(*args, **kwargs):
calls.append(args)
if args[:2] == ('systemctl', 'stop'):
raise subprocess.TimeoutExpired(args, 45)
return subprocess.CompletedProcess(args, 0, '', '')
with tempfile.TemporaryDirectory() as temporary:
p = Path(temporary)
with patch.object(display, 'SERVICE', p/'service'), \
patch.object(display, 'DROPIN', p/'dropin'), \
patch.object(display, 'CONFIG', p/'config'), \
patch.object(display, 'command', side_effect=command):
report = {}; display.restore(report)
self.assertIn(('systemctl', 'start', 'phosh.service'), calls)
self.assertTrue(report['restoredPhosh'])
self.assertEqual(len(report['cleanupErrors']), 1)