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,113 @@
# SPDX-License-Identifier: MPL-2.0
import hashlib
import importlib.util
import io
import json
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
from unittest.mock import patch
TOOLS = Path(__file__).resolve().parents[1]/'tools'
sys.path.insert(0,str(TOOLS))
import boot_backup
spec = importlib.util.spec_from_file_location('temporary_boot',TOOLS/'test-sargo-boot.py')
boot = importlib.util.module_from_spec(spec)
spec.loader.exec_module(boot)
class TemporaryBootTests(unittest.TestCase):
def test_different_phone_rejected_without_fastboot_queries(self):
with patch.object(boot,'getvar') as getvar:
with self.assertRaisesRegex(ValueError,'differs from the inventoried'):
boot.check_device('OTHER',hashlib.sha256(b'EXPECTED').hexdigest())
getvar.assert_not_called()
def test_locked_phone_and_slot_b_rejected(self):
expected = hashlib.sha256(b'SARGO').hexdigest()
for field,value in [('unlocked','no'),('current-slot','b'),('product','bonito'),('partition-size:boot_a','0x1000')]:
values = {'product':'sargo','unlocked':'yes','current-slot':'a','partition-size:boot_a':'0x4000000'}
values[field] = value
with patch.object(boot,'getvar',side_effect=lambda serial,name:values[name]):
with self.assertRaises(ValueError):
boot.check_device('SARGO',expected)
def test_mutating_fastboot_commands_are_not_implemented(self):
with patch.object(boot.subprocess,'run') as run:
for args in [('flash','boot_a','image.img'),('erase','userdata'),('set_active','b'),('flashing','unlock')]:
with self.assertRaises(ValueError):
boot.fastboot('SARGO',*args)
run.assert_not_called()
def test_fastboot_variable_formats(self):
for line in ['(bootloader) current-slot: a','current-slot: a']:
result = subprocess.CompletedProcess([],0,'',line+'\nFinished. Total time: 0.001s\n')
with patch.object(boot,'fastboot',return_value=result):
self.assertEqual(boot.getvar('SARGO','current-slot'),'a')
def test_default_mode_cannot_reboot_or_boot(self):
with patch.object(sys,'argv',['test-sargo-boot.py']), \
patch.object(boot,'checked_plan',return_value=({},Path('image.img'))), \
patch.object(boot,'reboot_from_droidian') as reboot, \
patch.object(boot,'fastboot') as fastboot, \
patch.object(boot,'find_fastboot') as find, \
patch.object(boot.os,'umask'), patch('sys.stdout',new_callable=io.StringIO):
boot.main()
reboot.assert_not_called()
fastboot.assert_not_called()
find.assert_not_called()
def test_collect_resumes_without_reboot_or_fastboot(self):
with tempfile.TemporaryDirectory() as temp:
root=Path(temp);logs=root/'logs/device';logs.mkdir(parents=True)
(root/'VALIDATION.json').write_text(json.dumps({'rawSlotADiagnostic':{}}))
image=root/'image.img';image.write_bytes(b'diagnostic')
sha=hashlib.sha256(image.read_bytes()).hexdigest()
previous={'operation':'fastboot boot','fastbootOutput':'Booting OKAY',
'imageSha256':sha,'serialSha256':'phone'}
(logs/'temporary-boot-original.json').write_text(json.dumps(previous))
plan={'diagnosticImageSha256':sha,'serialSha256':'phone'}
response={'status':'TUNDRA_USB_STATUS protocol=1 readOnly=true\nEND\n',
'version':'Linux version 4.9-124-google-sargo\nEND\n',
'mounts':'proc /proc proc ro 0 0\nEND\n',
'invalid':'ERROR unsupported command\nEND\n'}
with patch.object(sys,'argv',['test-sargo-boot.py','--collect']), \
patch.object(boot,'ROOT',root), \
patch.object(boot,'checked_plan',return_value=(plan,image)), \
patch.object(boot,'find_diagnostic',return_value=Path('/dev/bus/usb/003/011')), \
patch.object(boot,'device_layout',return_value={'interface':0,'in':129,'out':1}), \
patch.object(boot,'exchange',return_value=response), \
patch.object(boot,'reboot_from_droidian') as reboot, \
patch.object(boot,'fastboot') as fastboot, \
patch.object(boot.os,'umask'),patch('sys.stdout',new_callable=io.StringIO):
boot.main()
reboot.assert_not_called()
fastboot.assert_not_called()
reports=[json.loads(p.read_text()) for p in logs.glob('temporary-boot-*.json') if p.name!='temporary-boot-original.json']
self.assertEqual(len(reports),1)
self.assertTrue(reports[0]['passed'])
self.assertEqual(reports[0]['operation'],'usb collect')
self.assertEqual(reports[0]['previousBoot']['report'],'logs/device/temporary-boot-original.json')
validation=json.loads((root/'VALIDATION.json').read_text())
self.assertTrue(validation['rawSlotADiagnostic']['hardwareTested'])
self.assertFalse(validation['sargoHardwareDiagnostic']['gaiaIncluded'])
class RawBackupTests(unittest.TestCase):
def test_corruption_missing_file_and_unexpected_file_rejected(self):
with tempfile.TemporaryDirectory() as temp, patch.object(boot_backup,'SIZES',{'boot_a.img':4}):
folder=Path(temp);part=folder/'boot_a.img';part.write_bytes(b'boot')
m={'device':'sargo','rawPartitions':True,'files':{'boot_a.img':{'bytes':4,'sha256':hashlib.sha256(b'boot').hexdigest()}}}
manifest=folder/'manifest.json';manifest.write_text(json.dumps(m))
self.assertEqual(boot_backup.verify(folder),m)
part.write_bytes(b'bad!')
with self.assertRaisesRegex(ValueError,'checksum'):
boot_backup.verify(folder)
part.unlink()
with self.assertRaisesRegex(ValueError,'file or size'):
boot_backup.verify(folder)
m['files']['../escape']={};manifest.write_text(json.dumps(m))
with self.assertRaisesRegex(ValueError,'exactly'):
boot_backup.verify(folder)