Files
James Rich 0fc49ce537 Add a native test suite for lockdown redaction
Lockdown's core promise is that an unauthenticated local connection sees
nothing sensitive. Nothing asserted it. The gates in
PhoneAPI::getFromRadio() are #ifdef MESHTASTIC_PHONEAPI_ACCESS_CONTROL, and
no native env defined that, so every one of them compiled out of the test
build. Across 84 suites the only lockdown coverage was two cases in
test_stream_api, both on classifyLocalAdminPacket.

Adds [env:coverage-lockdown], which turns the lockdown flags on, and
test_lockdown_redaction, which drives a want_config handshake and checks what
actually reaches the client:

- security config: no private key, no public key, no admin keys
- bluetooth: fixed_pin zeroed
- network: wifi_psk withheld
- device metadata: whole struct wiped
- LoRa: reduced to the public whitelist - region, preset, channel_num and
  hop_limit survive; tx_power, override_frequency and the gain flag do not
- MQTT module config: broker username and password withheld
- channels: PSK and name emptied, and the handshake still reaches
  config_complete rather than stalling
- node DB: other nodes withheld (the DB is populated first, or "no nodes were
  sent" would be true of an empty one and prove nothing)
- inbound: an unauthorized client cannot inject mesh traffic but can still
  deliver lockdown_auth - refusing that too would make a locked node
  permanently unreachable
- with lockdown inactive, nothing is redacted at all: a capable build that was
  never provisioned must behave like stock firmware

Every case asserts both directions. A redaction test that only checks the
redacted side passes just as happily against a build that returns nothing to
anybody, which is not the property we want. Verified by mutation: stubbing
getAdminAuthorized() to always return true fails all eight redaction cases and
leaves the other two passing.

State is reset in setUp/tearDown rather than at the end of each test, because
Unity longjmps out of a failing assertion - inline cleanup would be skipped and
one red test would poison every test after it.

No nRF52 crypto is involved. The real EncryptedStorage hard-errors off
ARCH_NRF52, so the env drops it and links a stub in the suite directory that
keeps the one semantic the tests need: isLockdownActive() means "a DEK file
exists", which a test drives by creating /prefs/.dek.

Wired into CI through SPECIAL_ENVS in bin/test-shards.py, which gives the env
its own shard. The suite also lands in the general pool under plain
[env:coverage], where the flags are absent - it compiles to a single ignored
case there rather than breaking that shard. Both paths verified.
2026-09-15 06:59:44 -05:00
..
2022-08-11 17:54:48 -05:00
2024-02-21 10:03:45 -06:00
2026-07-16 18:35:33 -05:00
2026-06-30 12:44:02 -05:00
2026-08-06 14:05:07 +00:00
2024-07-15 07:11:37 -05:00
2024-10-06 07:55:02 -05:00
2025-10-19 08:52:56 +11:00