Update shared Gaia workflows and Sargo development tooling
Fix camera switching and Contacts/SMS activity routing across shared hosts. Integrate Marketplace installation and native standalone recovery tools, Bluetooth runtime packages and trusted certificates. Update English/French READMEs and the shared changelog with tested scope and remaining radio/audio/Bluetooth limitations. Preview17 remains the existing APK; no new native image is released. Validation: shared JavaScript and native Python tests; Android packaging and payload parity from an isolated publication checkout.
This commit is contained in:
parent
d04824ec89
commit
0041cd9660
101 changed files with 3883 additions and 335 deletions
69
tundra/tests/test_standalone_restore.py
Normal file
69
tundra/tests/test_standalone_restore.py
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# SPDX-License-Identifier: MPL-2.0
|
||||
import gzip
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
spec = importlib.util.spec_from_file_location('restore', Path(__file__).resolve().parents[1]/'tools/restore-standalone-sargo.py')
|
||||
restore = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(restore)
|
||||
|
||||
|
||||
class RestoreTests(unittest.TestCase):
|
||||
def make_backup(self, folder):
|
||||
payload = b'original userdata\0' * 100
|
||||
sha = hashlib.sha256(payload).hexdigest()
|
||||
data = {'archive': 'userdata-original.raw.gz', 'bytes': len(payload),
|
||||
'sha256': sha, 'checked': True, 'sourceWasUnmounted': True}
|
||||
(folder/data['archive']).write_bytes(gzip.compress(payload))
|
||||
(folder/'userdata.json').write_text(json.dumps(data))
|
||||
files = {}
|
||||
for name in ('boot_a.img', 'dtbo_a.img', 'vbmeta_a.img'):
|
||||
content = name.encode()
|
||||
(folder/name).write_bytes(content)
|
||||
files[name] = {'bytes': len(content), 'sha256': hashlib.sha256(content).hexdigest()}
|
||||
manifest = {'device': 'sargo', 'activeSlot': 'a', 'files': files,
|
||||
'userdataSha256': sha, 'userdataBytes': len(payload)}
|
||||
(folder/'recovery.json').write_text(json.dumps(manifest))
|
||||
return manifest
|
||||
|
||||
def test_review_verifies_backup_without_phone_commands(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
folder = Path(directory)
|
||||
self.make_backup(folder)
|
||||
with patch.object(sys, 'argv', ['restore', '--backup', directory]), \
|
||||
patch.object(restore.subprocess, 'run') as run, \
|
||||
patch.object(restore.subprocess, 'check_output') as read:
|
||||
restore.main()
|
||||
run.assert_not_called()
|
||||
read.assert_not_called()
|
||||
|
||||
def test_unbound_userdata_is_rejected(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
folder = Path(directory)
|
||||
manifest = self.make_backup(folder)
|
||||
manifest['userdataSha256'] = '0' * 64
|
||||
(folder/'recovery.json').write_text(json.dumps(manifest))
|
||||
with patch.object(sys, 'argv', ['restore', '--backup', directory]), \
|
||||
patch.object(restore.subprocess, 'run') as run:
|
||||
with self.assertRaisesRegex(ValueError, 'not bound'):
|
||||
restore.main()
|
||||
run.assert_not_called()
|
||||
|
||||
def test_altered_userdata_is_rejected(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
folder = Path(directory)
|
||||
self.make_backup(folder)
|
||||
(folder/'userdata-original.raw.gz').write_bytes(gzip.compress(b'changed'))
|
||||
with patch.object(sys, 'argv', ['restore', '--backup', directory]):
|
||||
with self.assertRaisesRegex(ValueError, 'Storage backup changed'):
|
||||
restore.main()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Loading…
Reference in a new issue