"""Offline, disposable checks for the opt-in Mapd shadow owner.""" import hashlib import json from multiprocessing import Process import os from pathlib import Path import struct import tempfile import unittest from typing import cast from unittest import mock from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params from openpilot.starpilot.maps.artifact import elf_arm64_static, source_digest from openpilot.starpilot.maps import shadow_lifecycle as shadow from openpilot.starpilot.maps import package_shadow def fake_static_elf() -> bytes: header = bytearray(64) header[:6] = b'\x7fELF\x02\x01' struct.pack_into(' str: assert key in (shadow.OPT_IN_KEY, 'SLCPriority1', 'SLCPriority2') return str(self.path if key == shadow.OPT_IN_KEY else self.path.parent / key) class FakeCar: notCar = False class TestShadowLifecycle(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() self.addCleanup(self.temp.cleanup) self.base = Path(self.temp.name).resolve() self.anchor = self.base / 'storage' self.root = shadow.map_offline_root(self.anchor) self.root.mkdir(parents=True) self.receipt = {'version': 1, 'sourceKind': 'local-pbf', 'sourceVerified': False, 'tileSchema': 'offline.capnp:0xda3a0d9284ca402f', 'attribution': '© OpenStreetMap contributors; https://www.openstreetmap.org/copyright (ODbL)', 'inputs': [{'name': 'synthetic.osm.pbf', 'size': 1, 'sha256': 'a' * 64}], 'tiles': [{'path': '34/-98/35.000000_-98.000000_35.250000_-97.750000', 'size': 1, 'sha256': 'b' * 64, 'empty': False}]} self.write_snapshot() self.source = self.base / 'source' self.source.mkdir() (self.source / 'main.go').write_text('pinned fixture') self.binary = self.base / 'mapd' self.binary.write_bytes(fake_static_elf()) self.binary.chmod(0o755) self.manifest = self.base / 'manifest.json' pin = json.loads((Path(BASEDIR) / 'upstream-sync.json').read_text()) revision = next(item['commit'] for item in pin['dependencies'] if item['path'] == 'mapd_repo') self.contents = {'schemaVersion': 1, 'goVersion': 'go1.25.1', 'target': 'linux-arm64-static', 'sourceDigest': source_digest(self.source), 'upstreamRevision': revision, 'sourceRevision': 'f' * 40} self.binary.write_bytes(self.binary.read_bytes() + '\n'.join((self.contents['sourceDigest'], revision, 'f' * 40)).encode()) self.contents['binarySha256'] = hashlib.sha256(self.binary.read_bytes()).hexdigest() self.write_manifest() def write_manifest(self): self.manifest.write_text(json.dumps(self.contents)) def write_snapshot(self): raw = json.dumps(self.receipt, separators=(',', ':')).encode() generation = hashlib.sha256(raw).hexdigest() directory = self.root / 'generations' / generation directory.mkdir(parents=True, exist_ok=True) (directory / 'receipt.json').write_bytes(raw) (self.root / 'current.json').write_text(json.dumps({'version': 1, 'generation': generation}, separators=(',', ':'))) return directory def preflight(self): return shadow.preflight(self.binary, self.manifest, self.root, self.source, self.anchor, self.base, self.base) def test_preflight_checks_real_binary_and_owned_root(self): self.assertTrue(elf_arm64_static(self.binary)) self.assertTrue(self.preflight()) self.contents['binarySha256'] = '0' * 64 self.write_manifest() self.assertFalse(self.preflight()) self.contents['binarySha256'] = hashlib.sha256(self.binary.read_bytes()).hexdigest() self.write_manifest() self.binary.chmod(0o644) self.assertFalse(self.preflight()) def test_rejects_manifest_fifo_symlink_oversize_and_dynamic_elf(self): self.manifest.unlink() os.mkfifo(self.manifest) self.assertFalse(self.preflight()) # must not block self.manifest.unlink() self.manifest.symlink_to(self.binary) self.assertFalse(self.preflight()) self.manifest.unlink() self.manifest.write_bytes(b' ' * (shadow.MAX_MANIFEST_BYTES + 1)) self.assertFalse(self.preflight()) self.write_manifest() data = bytearray(fake_static_elf()) struct.pack_into('