Harden Rivian angle and bridge safety

Keep Rivian angle commands below 4 m/s², exercise the common angle-safety coverage, and prevent generic firmware management from overwriting unverified external Black Pandas.

Original safety work based on PR #90 by TonyJOM (Anthony Orta).

Co-authored-by: TonyJOM <anthonyorta20@icloud.com>
This commit is contained in:
firestar5683
2026-08-16 11:26:25 -05:00
parent cb4ebf85a6
commit f2e6fddee9
6 changed files with 58 additions and 18 deletions
+9 -7
View File
@@ -77,13 +77,13 @@ def _flash_panda(panda: Panda) -> None:
def is_rivian_bridge_panda(panda: Panda, rivian: bool | None = None) -> bool:
if panda.is_internal() or panda.get_type() != Panda.HW_TYPE_BLACK:
return False
if rivian is None:
rivian = _is_rivian()
if rivian or panda.bootstub:
return rivian
# A cached Rivian CarParams record is not sufficient evidence to identify a
# bridge. An arbitrary external Black Panda may be connected at the same
# time, and flashing it would permanently replace its firmware. Only the
# signed bridge image can positively identify the hardware.
try:
expected_signature = Panda.get_signature_from_firmware(FW_PATH)
return panda.get_signature() == expected_signature
return not panda.bootstub and panda.get_signature() == expected_signature
except Exception:
return False
@@ -108,12 +108,14 @@ def prepare_rivian_bridge(panda_serials: list[str]) -> set[str]:
continue
bridge_confirmed = is_rivian_bridge_panda(panda, rivian)
if not bridge_confirmed:
if not bridge_confirmed and not rivian:
continue
bridge_serials.add(serial)
if rivian and firmware_available:
if bridge_confirmed and rivian and firmware_available:
_flash_panda(panda)
elif rivian:
cloudlog.warning(f"External Black Panda {serial} is not signed with the Rivian bridge firmware; leaving it untouched")
except Exception:
cloudlog.exception(f"Failed to prepare Rivian Extreme harness bridge {serial}")
finally:
@@ -46,8 +46,10 @@ def test_outdated_rivian_bridge_uses_bridge_flash_path():
panda_class.usb_list.return_value = ["bridge"]
panda_class.get_signature_from_firmware.return_value = b"expected"
# An unknown firmware image cannot be safely identified as the bridge and
# must be left to explicit provisioning instead of being overwritten.
assert flasher.prepare_rivian_bridge(["internal", "bridge"]) == {"bridge"}
flash_panda.assert_called_once_with(panda)
flash_panda.assert_not_called()
def test_non_rivian_matching_bridge_is_reserved_without_flashing():
@@ -78,3 +80,18 @@ def test_non_rivian_external_black_panda_is_not_misidentified():
assert flasher.prepare_rivian_bridge(["internal", "external"]) == set()
flash_panda.assert_not_called()
def test_bootstub_external_black_panda_is_not_misidentified():
panda = _external_black_panda(signature=b"expected", bootstub=True)
with patch.object(flasher, "_is_rivian", return_value=True), \
patch.object(flasher.os.path, "isfile", return_value=True), \
patch.object(flasher, "Panda", wraps=flasher.Panda) as panda_class, \
patch.object(flasher, "_flash_panda") as flash_panda:
panda_class.return_value = panda
panda_class.HW_TYPE_BLACK = b"\x03"
panda_class.usb_list.return_value = ["bridge"]
panda_class.get_signature_from_firmware.return_value = b"expected"
assert flasher.prepare_rivian_bridge(["bridge"]) == {"bridge"}
flash_panda.assert_not_called()