[esp32] Add software OTA downgrade protection (#17315)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Keith Burzinski
2026-07-06 20:39:18 -04:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 2dd7ac090f
commit d9998eff20
11 changed files with 254 additions and 0 deletions
+33
View File
@@ -13,6 +13,7 @@ from esphome.components.esp32 import (
VARIANT_ESP32,
VARIANTS,
NetworkSdkconfigData,
_ota_downgrade_protection_errors,
_reconcile_network_sdkconfig,
)
from esphome.components.esp32.const import (
@@ -560,3 +561,35 @@ def test_network_wifi_ble_coexistence_reconciles_end_to_end(
assert sdkconfig.get("CONFIG_LWIP_DHCPS") is False
# WiFi present alongside BT -> WiFi stack must stay enabled.
assert "CONFIG_ESP_WIFI_ENABLED" not in sdkconfig
def test_downgrade_protection_passes_with_numeric_version_and_signing() -> None:
assert _ota_downgrade_protection_errors("1.2.3", signed_ota_enabled=True) == []
def test_downgrade_protection_accepts_calendar_version() -> None:
assert _ota_downgrade_protection_errors("2024.12.0", signed_ota_enabled=True) == []
def test_downgrade_protection_requires_project_version() -> None:
errs = _ota_downgrade_protection_errors(None, signed_ota_enabled=True)
assert len(errs) == 1
assert "version" in str(errs[0])
def test_downgrade_protection_rejects_non_numeric_version() -> None:
errs = _ota_downgrade_protection_errors("1.0-beta", signed_ota_enabled=True)
assert len(errs) == 1
assert "dotted-numeric" in str(errs[0])
def test_downgrade_protection_requires_signed_ota() -> None:
errs = _ota_downgrade_protection_errors("1.2.3", signed_ota_enabled=False)
assert len(errs) == 1
assert "signed_ota_verification" in str(errs[0])
def test_downgrade_protection_reports_all_unmet_requirements() -> None:
# No project version and no signing -> two distinct errors.
errs = _ota_downgrade_protection_errors(None, signed_ota_enabled=False)
assert len(errs) == 2