Files
wadamesh/scripts/lua-harness
Kaj SchittecatandClaude Opus 5 6868911f59 touch: SD Scan, find and remove Windows malware on the SD card
Some ThinkNode M9 cards shipped with a dormant Windows worm (Elecrow
security advisory, September 2026). An infected card seen since carries
autorun.inf in the root, launching xlfqf.pif on open, explore and autoplay
with random-junk comment lines in between: the Sality autorun pattern.

- SD Scan store app (deploy/apps/sdscan/1.0, requires "sd", not seeded):
  walks the card a small page per tick, lists what it finds and why, and
  removes it after a confirmation screen with Cancel first. It says on
  every screen that it only removes files it recognises and that
  formatting the card is the safe fix. On older firmware it still finds
  threats by name but cannot remove them.
- Firmware: wada.sd.check(path) and wada.sd.remove(path), plus paging for
  wada.sd.list(path, start, max) and caps().sd_clean. What counts as a
  threat lives in SdThreat.h: autorun.inf, Windows program, script and
  shortcut extensions, or a real MZ+PE header under any name. remove()
  classifies again in firmware and refuses anything else, so no app can
  use it to delete tiles, backups or chat history. It clears read-only,
  hidden and system first, because FAT refuses to delete a read-only file.
- A warning when a card with Windows malware in its top folder is mounted,
  at boot or on insert, offering SD Scan (or the Store).
- Tests: test/test_sd_threat.cpp, and SD Scan harness scenarios including
  the real infected card's root. Removal checked on a T-Deck.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 13:33:30 +02:00
..
2026-08-25 16:12:24 -04:00

Host harness for Wadamesh Lua apps

Runs a Store app on your desktop, against a mock of the wada.* host, before it ever touches a device. Not part of the firmware build.

scripts/lua-harness/run.sh                                   # gpscompass, all scenarios
scripts/lua-harness/run.sh deploy/apps/wardrive/1.1/wardrive.lua
SCENARIO=declination scripts/lua-harness/run.sh              # one scenario

run.sh compiles luah on first use (and whenever main.c changes) from the Lua sources already vendored in lib/lua/src — no dependency beyond a C compiler.

What makes it worth running

It is built from the same vendored Lua 5.4.7 as the firmware, with the same LUA_32BITS numeric model — 32-bit integers, single-precision floats. That is the point. Maths that behaves in a desktop float64 interpreter can lose catastrophic precision on the device, and this is where that shows up.

The mock mirrors LuaAppHost.cpp rather than being convenient: the same argument type-checks, the same 100k-instruction budget per callback, the same event shapes, and the same store restrictions. That has caught real defects — the device store accepts strings and numbers only, and a boolean flag thrown inside a guarded callback looks exactly like a keypress doing nothing at all.

Device attitude is simulated physically, not faked: a magnetic field of the right magnitude and dip, rotated into the body frame by heading/roll/pitch, plus the hard-iron and zero-g biases measured on a real M9. So calibration, tilt compensation and heading all get exercised for real.

Scenarios

harness.lua holds them all. Board shapes — M9 320x196 landscape, V4/R8 portrait, base-SDK V4 (no extended SDK), Pager, Pager portrait at Jumbo font sizes, Tanmatsu — plus an instruction-cost probe that fails the run if any tick exceeds a quarter of the budget.

Three are about the compass being correct rather than merely working:

  • declination — pulls the generated WMM block straight out of the app file and checks it against NOAA reference values at six sites, including a weak-field one near the pole. Testing the shipped bytes, not a copy, so a bad regeneration fails here rather than on hardware. See scripts/wmm/.
  • bearings_absolute — contacts placed due N/E/S/W and NE of the fix, to check bearings against absolute compass directions. The older marker test compares each drawn dot against the app's own bearing, which stays self-consistent even if east and west are swapped; this one would not. The north-east case is what separates a mirror from a lat/lon transpose (38.3° vs 51.7°).
  • align_nofix — "set north" pressed with no position at all. The offset it stores silently swallows the whole declination, so the app has to give it back when the first fix lands, or the heading is wrong by twice it.

Reading a failure

Scenarios print what they saw before asserting, so a failure usually names the cause. Two conventions worth knowing:

  • The dial centre is read out of the canvas draw order: digits, degree sign, T/M reference, cardinal. Add anything to that sequence and the index offsets in the assertions move with it.
  • APP ERROR: means the app raised inside a guarded callback — the harness keeps going, and the scenario fails later on a symptom. The first APP ERROR line is the real one.