phase: 02_tls_control_channel
**Verified / implemented (phase 02 final pass)** - All 6 tasks already in `complete/` → verification pass. Device measurement **found a real defect (README bug 11)**: the cert carried its SAN *value* under the OID written from the ASCII text `"2.5.29.17"` instead of DER content bytes `55 1D 11` (`openssl x509 -text` showed `1.10.46.53…`, hex `30 2f 06 09 32 2e 35…`), i.e. **no SAN** → hostname validation impossible while every host check stayed green (they walked the value, never the label). - Fixed in the pure module: `kSanOidTlv`/`sanOidDer()`, `sanExtensionFullDer()` (pinned to the 43 bytes OpenSSL writes for these names), `derCarriesSan()` (OID *and* value); `tls.cpp` uses them + 3 `static_assert`s; `cert` now warns and names the remedy. 33 new checks in `test_tls_pem.cpp`, incl. the pre-fix extension byte-for-byte (`derContains` yes / `derCarriesSan` no). - Corrected a false finding: the earlier "fingerprint rotated once" was an **OpenSSL `-ext` artifact** (`C8:76…` vs the real `61:54:19:30…`, same DER). Re-measured: serial `cert` == live handshake DER hash; page 51 626 B, `sha256 dd16e195…f04e9` == locally assembled page. **Tests / lint (100 % green)** - `bash .agents/validate.sh` → **GATE_EXIT=0**: `RESULT: all suites passed` in the plain *and* `SANITIZE=1` run, **4826 checks / 0 failures** each; `bridge`/`console`/`rollback` **SUCCESS**; `page bytes: 51626`; `README/AGENTS claims: OK`; `repo hygiene: OK (71 tracked files)`. - Footprint: bridge **RAM 30.4 % (99 616 B) / Flash 39.6 % (1 246 145 B)** vs baseline 26.7 %/87 592 & 36.1 %/1 135 293 → **+12 024 B RAM / +110 852 B flash**; TLS alone +6 160 B / +100 008 B (rollback image byte-identical); session heap 187 936 → ~145.5 k (1 session) → ~107.9 k (2). - `ruff check --select F,E9 tools/ tests/` → All checks passed; `bash -n` clean (gate, runner, probe); `-Wall -Wextra` warning-free. **Completion criteria**: 1 ✓ (gate green + RAM/Flash + session heap quoted); 2 ✓ as recorded (boot prints no fingerprint on the NVS-load path, `cert` prints on demand, identity survived reflashes, nothing about the key is printed anywhere — `nvs erase`→first-boot leg **not re-run**); 3 ✓ re-measured (51 626 == gate; `:80` → 301, no page bytes); 4 partial — 426/401/404 + pinning handshake measured, but arming/typing needs the operator's passphrase (`dflt:0`) and the target is this machine, so no input was sent; 5 ✓ (no `.pem/.key/.crt` tracked or on disk; hygiene block ran); 6 ✓ (`[env:rollback]` built every run + README section); 7 ✓. **Documentation**: README — check count 4793→4826 (intro + Quick start), `test_tls_pem` 829→862 with new pins, footprint/TLS-cost rows re-measured, "Ten bugs"→"Eleven bugs" + new entry + both anchors, `cert` row, Troubleshooting names-warning row, `tls_pem.h` architecture entry, nine/ten pure-module wording. AGENTS.md (staleness only): "Ten bugs"→"Eleven bugs" ×2, 4826, and the certificate-names row extended with the DER-OID rule. `.agents/HW_VERIFICATION.md` — 426 body/headers re-measured, fingerprint row correction + `-ext` rule, new SAN row (`failed → fixed in tree, device leg needs nvs erase`) with closing commands; phase report written to `.agents/reports/02_tls_control_channel/02_tls_control_channel__00_phase.a1.md`. **Deviations / live-infra**: made **no** reflash and **no** `nvs erase` (erase also destroys the token and Wi-Fi credentials; flashing puts a live HID keyboard into ROM download mode on this machine). Live steps were read-only `curl`/`openssl` plus one capped `console.py cert` (opening the CDC resets the board — permitted, recorded). No phase/PLAN files touched; everything left in the working tree for the harness to commit. **Next pending phase**: `03_session_takeover` — `01_pending_claim_socket.md`.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
**Verified / implemented (phase 02 final pass)**
|
||||
- All 6 tasks already in `complete/` → verification pass. Device measurement **found a real defect (README bug 11)**: the cert carried its SAN *value* under the OID written from the ASCII text `"2.5.29.17"` instead of DER content bytes `55 1D 11` (`openssl x509 -text` showed `1.10.46.53…`, hex `30 2f 06 09 32 2e 35…`), i.e. **no SAN** → hostname validation impossible while every host check stayed green (they walked the value, never the label).
|
||||
- Fixed in the pure module: `kSanOidTlv`/`sanOidDer()`, `sanExtensionFullDer()` (pinned to the 43 bytes OpenSSL writes for these names), `derCarriesSan()` (OID *and* value); `tls.cpp` uses them + 3 `static_assert`s; `cert` now warns and names the remedy. 33 new checks in `test_tls_pem.cpp`, incl. the pre-fix extension byte-for-byte (`derContains` yes / `derCarriesSan` no).
|
||||
- Corrected a false finding: the earlier "fingerprint rotated once" was an **OpenSSL `-ext` artifact** (`C8:76…` vs the real `61:54:19:30…`, same DER). Re-measured: serial `cert` == live handshake DER hash; page 51 626 B, `sha256 dd16e195…f04e9` == locally assembled page.
|
||||
|
||||
**Tests / lint (100 % green)**
|
||||
- `bash .agents/validate.sh` → **GATE_EXIT=0**: `RESULT: all suites passed` in the plain *and* `SANITIZE=1` run, **4826 checks / 0 failures** each; `bridge`/`console`/`rollback` **SUCCESS**; `page bytes: 51626`; `README/AGENTS claims: OK`; `repo hygiene: OK (71 tracked files)`.
|
||||
- Footprint: bridge **RAM 30.4 % (99 616 B) / Flash 39.6 % (1 246 145 B)** vs baseline 26.7 %/87 592 & 36.1 %/1 135 293 → **+12 024 B RAM / +110 852 B flash**; TLS alone +6 160 B / +100 008 B (rollback image byte-identical); session heap 187 936 → ~145.5 k (1 session) → ~107.9 k (2).
|
||||
- `ruff check --select F,E9 tools/ tests/` → All checks passed; `bash -n` clean (gate, runner, probe); `-Wall -Wextra` warning-free.
|
||||
|
||||
**Completion criteria**: 1 ✓ (gate green + RAM/Flash + session heap quoted); 2 ✓ as recorded (boot prints no fingerprint on the NVS-load path, `cert` prints on demand, identity survived reflashes, nothing about the key is printed anywhere — `nvs erase`→first-boot leg **not re-run**); 3 ✓ re-measured (51 626 == gate; `:80` → 301, no page bytes); 4 partial — 426/401/404 + pinning handshake measured, but arming/typing needs the operator's passphrase (`dflt:0`) and the target is this machine, so no input was sent; 5 ✓ (no `.pem/.key/.crt` tracked or on disk; hygiene block ran); 6 ✓ (`[env:rollback]` built every run + README section); 7 ✓.
|
||||
|
||||
**Documentation**: README — check count 4793→4826 (intro + Quick start), `test_tls_pem` 829→862 with new pins, footprint/TLS-cost rows re-measured, "Ten bugs"→"Eleven bugs" + new entry + both anchors, `cert` row, Troubleshooting names-warning row, `tls_pem.h` architecture entry, nine/ten pure-module wording. AGENTS.md (staleness only): "Ten bugs"→"Eleven bugs" ×2, 4826, and the certificate-names row extended with the DER-OID rule. `.agents/HW_VERIFICATION.md` — 426 body/headers re-measured, fingerprint row correction + `-ext` rule, new SAN row (`failed → fixed in tree, device leg needs nvs erase`) with closing commands; phase report written to `.agents/reports/02_tls_control_channel/02_tls_control_channel__00_phase.a1.md`.
|
||||
|
||||
**Deviations / live-infra**: made **no** reflash and **no** `nvs erase` (erase also destroys the token and Wi-Fi credentials; flashing puts a live HID keyboard into ROM download mode on this machine). Live steps were read-only `curl`/`openssl` plus one capped `console.py cert` (opening the CDC resets the board — permitted, recorded). No phase/PLAN files touched; everything left in the working tree for the harness to commit.
|
||||
|
||||
**Next pending phase**: `03_session_takeover` — `01_pending_claim_socket.md`.
|
||||
@@ -0,0 +1 @@
|
||||
ok
|
||||
@@ -0,0 +1,205 @@
|
||||
== host suites: bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 862 checks, 0 failures
|
||||
test_tls_session 118 checks, 0 failures
|
||||
test_conn 268 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
one routing path, two transports
|
||||
the client side of pinning
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 271 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
the connect path
|
||||
the channel pill and the certificate line
|
||||
element ids
|
||||
page 113 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== host suites: SANITIZE=1 bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
sanitizers: on
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 862 checks, 0 failures
|
||||
test_tls_session 118 checks, 0 failures
|
||||
test_conn 268 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
one routing path, two transports
|
||||
the client side of pinning
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 271 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
the connect path
|
||||
the channel pill and the certificate line
|
||||
element ids
|
||||
page 113 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== firmware: platformio run -e bridge -e console -e rollback ==
|
||||
Processing bridge (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/bridge/partitions.bin
|
||||
Retrieving maximum program size .pio/build/bridge/firmware.elf
|
||||
Checking size .pio/build/bridge/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [=== ] 30.4% (used 99616 bytes from 327680 bytes)
|
||||
Flash: [==== ] 39.6% (used 1246145 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.87 seconds =========================
|
||||
|
||||
Processing console (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/console/partitions.bin
|
||||
Retrieving maximum program size .pio/build/console/firmware.elf
|
||||
Checking size .pio/build/console/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [== ] 20.5% (used 67224 bytes from 327680 bytes)
|
||||
Flash: [==== ] 37.1% (used 1166397 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.86 seconds =========================
|
||||
|
||||
Processing rollback (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/rollback/partitions.bin
|
||||
Retrieving maximum program size .pio/build/rollback/firmware.elf
|
||||
Checking size .pio/build/rollback/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [=== ] 28.5% (used 93456 bytes from 327680 bytes)
|
||||
Flash: [==== ] 36.4% (used 1146137 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.86 seconds =========================
|
||||
|
||||
Environment Status Duration
|
||||
------------- -------- ------------
|
||||
bridge SUCCESS 00:00:00.871
|
||||
console SUCCESS 00:00:00.860
|
||||
rollback SUCCESS 00:00:00.857
|
||||
========================= 3 succeeded in 00:00:02.588 =========================
|
||||
|
||||
== page size: src/web_page.h raw strings ==
|
||||
page bytes: 51626 (a reflashed device must serve exactly this many; kIndexHtmlLen is sizeof(kIndexHtml)-1 of these same bytes, both builds)
|
||||
|
||||
== README/AGENTS claims vs what this run measured ==
|
||||
README/AGENTS claims: OK (4 826 checks quoted and measured in both runs; 11 Tests-table rows match their suites; 51 626 page bytes quoted; Backlog contiguous; every ws:// sentence names the rollback)
|
||||
|
||||
== repo hygiene ==
|
||||
repo hygiene: OK (71 tracked files, no ignored-tracked files, no key-material shapes, no PII hits)
|
||||
|
||||
== hardware context (informational; cannot change the gate result) ==
|
||||
hw-probe serial /dev/ttyACM0 present, readable (NOT opened: opening toggles DTR/RTS and resets the board)
|
||||
hw-probe mdns keyrelay.local resolves -> 10.2.0.22
|
||||
hw-probe https https://keyrelay.local/ -> HTTP 200 (TLS listener is up)
|
||||
hw-probe http http://keyrelay.local/ -> HTTP 301, redirects to https://keyrelay.local/ (redirect-only: the post-phase-02 shape)
|
||||
hw-probe tls 10.2.0.22:443 negotiated TLSv1.2 / ECDHE-ECDSA-AES256-GCM-SHA384 (a self-signed verify failure is the expected shape; the fingerprint to compare it against is on the serial console)
|
||||
hw-probe uv /home/ducoterra/.local/bin/uv — firmware builds available
|
||||
hw-probe node /usr/bin/node — test_page.js runs
|
||||
hw-probe evdev board 046d:c33f visible: keyboard=/dev/input/event19 (readable) mouse=/dev/input/event20 (readable) — python3 tools/watch_target.py runs ON THIS machine (the target)
|
||||
validation OK (suites + sanitised suites + bridge/console/rollback builds + page size
|
||||
+ the numbers README/AGENTS quote + hygiene)
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
**Implemented**
|
||||
- `src/tls_pem.h` (new, pure — no Arduino/IDF/mbed includes): `wrapPem`/`pemFind` PEM armour both ways, `fingerprintHex`, the single `sanEntries()` name table + `subjectLine()`/`sanList()`, hand-built SAN GeneralNames DER, strict `ipv4Bytes`, and `__DATE__`/`addDays`/`addYears`/`utcTime` validity arithmetic.
|
||||
- `src/tls.h` + `src/tls.cpp` (mbed TLS half): `generateIdentity()` (secp256r1 → self-signed SHA-256 cert, DRBG personalisation `"keyrelay"`, SAN extension, ±validity window, SHA-256 fingerprint), `selfCheck()` (reparse + `pk_check_pair`), `certificateFingerprint()`, `lastError()`; RAII context wrappers free everything on every error path; `#if KR_TLS == 0` stubs keep the rollback linkable. Header records the ld_libs/sdkconfig/nm evidence.
|
||||
- `src/config.h`: `KR_TLS` (default 1), `kCertCommonName`, `kCertValidityYears`, `kPemMax=1024` with measured numbers; `platformio.ini`: `-DKR_TLS=1` in both envs with the rollback named.
|
||||
- SAN is encoded by tested code (OID 2.5.29.17 via `set_extension`) rather than the library's version-varying SAN struct; the 34 DER bytes were verified byte-identical to OpenSSL's for the same names.
|
||||
|
||||
**Verification** (all green)
|
||||
- `bash .agents/validate.sh` → `validation OK`; suites + `SANITIZE=1` both `RESULT: all suites passed`, **4170 checks** (3162 C++ + **764** `test_tls_pem` + 160 relayctl + 84 page), `test_proto` untouched at 2327, page bytes 48 598, hygiene OK, no key-material shapes.
|
||||
- gcov: **src/tls_pem.h 100.00 % of 305 lines** (requirement >90 %); `src/tls.*` stated, not faked.
|
||||
- Firmware: `bridge` 26.7 % RAM / 36.1 % Flash and `console` 16.8 % / 33.6 % — **unchanged from baseline** because nothing calls the identity yet (`--gc-sections` drops it). Proved that is not a false pass: an injected undefined symbol in `tls.cpp` linked anyway, so I re-linked a scratch copy with `-Wl,-u,` forcing the three functions in → both envs link all mbed TLS symbols; cost then `bridge` **88 304 B RAM (+712) / 1 170 853 B Flash (+35 560)**, `console` 55 904 / 1 091 181. `-D KR_TLS=0` builds both envs at exactly the pre-phase footprint.
|
||||
- Found and fixed a real defect via the cross-check: `wrapPem` omitted the newline after a padded final group (1/2 bytes mod 48) — round-trips fine, but not what any other tool writes.
|
||||
|
||||
**Docs**: README (check count ×2, architecture map, pure-module count, Tests table row, "gaps" paragraph — explicit that the identity is not on the wire yet). AGENTS.md stale facts only (check count, pure-module list now including `tls_pem.h` + the no-crypto-library rule, a name-table row, the "fingerprint yes, key never" clause).
|
||||
|
||||
**Decisions**: no device changes — nothing is reachable over TLS yet, so no `HW_VERIFICATION.md` row was run or recorded; `.agents/HW_VERIFICATION.md`'s 3406 baseline left as the phase-01 delta anchor.
|
||||
|
||||
**Next pending task**: `.agents/phases/todo/02_tls_control_channel/02_identity_persistence.md` (NVS storage, generate-once, serial `cert`, `StatusSnapshot` visibility).
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
== host suites: bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2327 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 764 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 160 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
element ids
|
||||
page 84 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== host suites: SANITIZE=1 bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
sanitizers: on
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2327 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 764 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 160 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
element ids
|
||||
page 84 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== firmware: platformio run -e bridge -e console ==
|
||||
Processing bridge (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/bridge/partitions.bin
|
||||
Retrieving maximum program size .pio/build/bridge/firmware.elf
|
||||
Checking size .pio/build/bridge/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [=== ] 26.7% (used 87592 bytes from 327680 bytes)
|
||||
Flash: [==== ] 36.1% (used 1135293 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.84 seconds =========================
|
||||
|
||||
Processing console (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/console/partitions.bin
|
||||
Retrieving maximum program size .pio/build/console/firmware.elf
|
||||
Checking size .pio/build/console/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [== ] 16.8% (used 55200 bytes from 327680 bytes)
|
||||
Flash: [=== ] 33.6% (used 1056081 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.85 seconds =========================
|
||||
|
||||
Environment Status Duration
|
||||
------------- -------- ------------
|
||||
bridge SUCCESS 00:00:00.845
|
||||
console SUCCESS 00:00:00.853
|
||||
========================= 2 succeeded in 00:00:01.698 =========================
|
||||
|
||||
== page size: src/web_page.h raw string ==
|
||||
page bytes: 48598 (a reflashed device must serve exactly this many; kIndexHtmlLen is sizeof(kIndexHtml)-1 of this same string)
|
||||
|
||||
== repo hygiene ==
|
||||
repo hygiene: OK (71 tracked files, no ignored-tracked files, no key-material shapes, no PII hits)
|
||||
|
||||
== hardware context (informational; cannot change the gate result) ==
|
||||
hw-probe serial /dev/ttyACM0 present, readable (NOT opened: opening toggles DTR/RTS and resets the board)
|
||||
hw-probe mdns keyrelay.local resolves -> 10.2.0.22
|
||||
hw-probe https https://keyrelay.local/ unreachable (curl rc 7, code 000) — expected until phase 02 (TLS) lands
|
||||
hw-probe http http://keyrelay.local/ -> HTTP 200, no redirect (plaintext page still served: the pre-phase-02 shape)
|
||||
hw-probe uv /home/ducoterra/.local/bin/uv — firmware builds available
|
||||
hw-probe node /usr/bin/node — test_page.js runs
|
||||
hw-probe evdev board 046d:c33f visible: keyboard=/dev/input/event19 (readable) mouse=/dev/input/event20 (readable) — python3 tools/watch_target.py runs ON THIS machine (the target)
|
||||
validation OK (suites + sanitised suites + bridge/console builds + page size + hygiene)
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
**Implementation** (`02_tls_control_channel/02_identity_persistence`)
|
||||
|
||||
- `src/main.cpp`: identity now lives in NVS (`tlscrt`/`tlskey`/`tlscrtfp`); `loadTlsIdentity()` runs at boot before `control.begin()` — loads and `selfCheck()`s the stored pair, else generates, stores and prints the fingerprint **once**; a corrupt record is regenerated with two loud `!!` lines before the new value ("any fingerprint you pinned is now wrong"). Store does a read-back (lengths compared, contents never) and prints `IDENTITY NOT STORED … do not pin this fingerprint` if NVS refuses/truncates. All PEM helpers are inside `#if KR_TLS`.
|
||||
- Serial `cert` (no argument form, in `help`): SHA-256 fingerprint (two 47-char lines, not one 95-char line — 128-byte CDC ring, README bug 1), validity window from the stored cert, and the names from `sanEntries()`, with a `!!` warning when `derContains()` shows the stored cert does not carry that table. No command writes or dumps a key/cert; `git grep -i "private key" src/` returns only prose comments and the `kPemKeyLabel`/mbedTLS API names.
|
||||
- New pure `src/status.h`: `StatusSnapshot` + `statusJson()` moved out of `control_server.{h,cpp}` so the frame is host-testable, plus `tls` and `fp` (first 8 bytes of the fingerprint in hex, `fp:""` whenever `tls:0`; a non-hex `fp` is cut so a stored value cannot forge a JSON field). `src/tls_pem.h` gained `fingerprintPairs`, `fingerprintPrefix`, `derContains`, `dateTimeText`, `sanEntries()`; `src/tls.{h,cpp}` gained `certificateDetails()` (+ `KR_TLS==0` stub) and the `tls.cpp` docstring.
|
||||
- Tests: `test_tls_pem.cpp` +97 checks (pinned name table incl. `CN == kHostname + ".local"`, both printed fingerprint shapes rejoining to the digest and refusing at `cap`, `derContains` breaking on one changed byte either side, `dateTimeText`); `test_proto.cpp` + status-frame suite (fields, sanitising, longest legal frame **322 B ≤ `kStatusJsonCap` 384**, renders as nothing when 1 B short).
|
||||
|
||||
**Results:** `bash .agents/validate.sh` → `validation OK` (exit 0). `tests/run_tests.sh`: **4267 checks, 0 failures** (proto 2359, tls_pem 829, text 459, relayctl 160, output 153, ws_codec 135, page 84, mouse 48, keystate 40); same under `SANITIZE=1`. Coverage: `src/tls_pem.h` 100.00 % of 367, `src/status.h` 100.00 % of 28. `pio run -e bridge -e console` SUCCESS — bridge RAM 27.6 % (90 432 B) / Flash 37.5 %, console 17.7 %/34.9 %. Rollback `-DKR_TLS=0` (out-of-tree copy) builds both envs: RAM 26.8 %, Flash 36.1 %, no new warnings.
|
||||
|
||||
**Docs:** README — check count 3406→4267, Quick-start first-boot fingerprint block + survive-reflashing/re-pin rule, `cert` in the serial-console table, `tls`/`fp` in the Wire-protocol status row, architecture map (`status.h`, `tls_pem.h`, `tls.{h,cpp}`, `test_tls_pem.cpp`), Tests-table rows, NVS design decision, 3 troubleshooting rows, note that the measured transcript predates these fields. AGENTS.md — check count and the pure-module list (`status.h`).
|
||||
|
||||
**Deviations:** (1) fingerprint printed as wrapped colon-pair lines, not one 64-hex line; (2) status `fp` is a 16-char label, not the full digest — the cap and the page can't carry 64 hex usefully; (3) `StatusSnapshot`/`statusJson` moved modules (needed for the host-measured cap); (4) added `certificateDetails()` and the four `tls_pem.h` helpers as the tested seams `cert`/status need; (5) boot-time store read-back added to honour "if it does not fit, say so" — the API otherwise fails silently.
|
||||
|
||||
**Device pass (next, not run here):** `console.py cert` → `reboot` → same fingerprint + `identity loaded from NVS`; `nvs erase` + reboot → `identity generated`, pin it, reboot again → unchanged; `console.py status` shows `"tls":1,"fp":"<16 hex>"` matching `cert`'s first 8 bytes.
|
||||
|
||||
Next task: `.agents/phases/todo/02_tls_control_channel/03_tls_listener.md`.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
== host suites: bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 160 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
element ids
|
||||
page 84 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== host suites: SANITIZE=1 bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
sanitizers: on
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 160 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
element ids
|
||||
page 84 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== firmware: platformio run -e bridge -e console ==
|
||||
Processing bridge (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/bridge/partitions.bin
|
||||
Retrieving maximum program size .pio/build/bridge/firmware.elf
|
||||
Checking size .pio/build/bridge/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [=== ] 27.6% (used 90432 bytes from 327680 bytes)
|
||||
Flash: [==== ] 37.5% (used 1178749 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.86 seconds =========================
|
||||
|
||||
Processing console (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/console/partitions.bin
|
||||
Retrieving maximum program size .pio/build/console/firmware.elf
|
||||
Checking size .pio/build/console/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [== ] 17.7% (used 58040 bytes from 327680 bytes)
|
||||
Flash: [=== ] 34.9% (used 1099237 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.86 seconds =========================
|
||||
|
||||
Environment Status Duration
|
||||
------------- -------- ------------
|
||||
bridge SUCCESS 00:00:00.863
|
||||
console SUCCESS 00:00:00.865
|
||||
========================= 2 succeeded in 00:00:01.727 =========================
|
||||
|
||||
== page size: src/web_page.h raw string ==
|
||||
page bytes: 48598 (a reflashed device must serve exactly this many; kIndexHtmlLen is sizeof(kIndexHtml)-1 of this same string)
|
||||
|
||||
== repo hygiene ==
|
||||
repo hygiene: OK (71 tracked files, no ignored-tracked files, no key-material shapes, no PII hits)
|
||||
|
||||
== hardware context (informational; cannot change the gate result) ==
|
||||
hw-probe serial /dev/ttyACM0 present, readable (NOT opened: opening toggles DTR/RTS and resets the board)
|
||||
hw-probe mdns keyrelay.local did not resolve within 4 s (no responder? glibc does not cache mDNS — a retry may still work; the IP is the fallback)
|
||||
hw-probe https https://keyrelay.local/ unreachable (curl rc 28, code 000) — expected until phase 02 (TLS) lands
|
||||
hw-probe http http://keyrelay.local/ -> HTTP 200, no redirect (plaintext page still served: the pre-phase-02 shape)
|
||||
hw-probe uv /home/ducoterra/.local/bin/uv — firmware builds available
|
||||
hw-probe node /usr/bin/node — test_page.js runs
|
||||
hw-probe evdev board 046d:c33f visible: keyboard=/dev/input/event19 (readable) mouse=/dev/input/event20 (readable) — python3 tools/watch_target.py runs ON THIS machine (the target)
|
||||
validation OK (suites + sanitised suites + bridge/console builds + page size + hygiene)
|
||||
@@ -0,0 +1,12 @@
|
||||
**Task complete: `02_tls_control_channel/03_tls_listener.md`**
|
||||
|
||||
**Implemented** — TLS control-channel listener on `:443`, raw mbedTLS driven from `tick()`:
|
||||
- `src/tls_session.{h,cpp}` — one non-blocking server session per accepted fd; handshake = one `mbedtls_ssl_handshake()` per tick with a `kTlsHandshakeMs` deadline; strict same-buffer write-resume contract; slot-cap refusal renders the 7-byte RFC 5246 fatal alert without building a context. Pure policy half (deadline, admission, return-code table, alert, write queue, frame ring) host-tested; library half behind `KR_TLS && ESP_PLATFORM`.
|
||||
- `src/control_server.{h,cpp}` — `:443` listener + plaintext `:80` feed **one** controller slot via one `admitConnection()` rule (cap 2, no transport parameter); per-slot response pumps (page leaves 4 KB/tick); WS frames whole-or-dropped via `TxRing`; `KR_TLS=0` rollback intact.
|
||||
- Device logs only sessions + heap; `hw_probe.sh` gained an informational TLS probe.
|
||||
|
||||
**Tests** — `tests/test_tls_session.cpp` (135 checks; 100 % coverage of the pure half, ASan/UBSan clean); suite now **4402 checks**, green normal + sanitised; `validate.sh` **validation OK** (both firmware builds, page bytes, hygiene).
|
||||
|
||||
**Device pass** (board flashed and verified live): TLSv1.2/**ECDHE-ECDSA-AES256-GCM-SHA384**; page over `https` = 48598 B = gate count; `/status` 401 without token over TLS; console `cert` == handshake fingerprint, stable across 2 reflashes + 3 reboots; heap 187.9 k boot → 145.5 k (1 session) → 107.9 k (2), 20 cycles no drift; 3rd connection refused with alert 40 in 0.0 s; stalled handshake never blocked `loop()` and died on the ~10 s deadline; `:80` untouched (task 04's territory). Results recorded in `.agents/HW_VERIFICATION.md`.
|
||||
|
||||
**Found & fixed during verification**: one silent identity rotation happened on the first boot under the new firmware with nothing observable about it — `loadTlsIdentity()`/`storeTlsIdentity()` now name the failing gate with lengths only. README/AGENTS.md updated (check counts, security model, new pinned-table row). No phase files touched; nothing staged; board left running the new firmware, not in download mode.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
== host suites: bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
test_tls_session 135 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 160 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
element ids
|
||||
page 84 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== host suites: SANITIZE=1 bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
sanitizers: on
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
test_tls_session 135 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 160 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
element ids
|
||||
page 84 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== firmware: platformio run -e bridge -e console ==
|
||||
Processing bridge (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/bridge/partitions.bin
|
||||
Retrieving maximum program size .pio/build/bridge/firmware.elf
|
||||
Checking size .pio/build/bridge/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [=== ] 29.6% (used 97136 bytes from 327680 bytes)
|
||||
Flash: [==== ] 39.4% (used 1238321 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.86 seconds =========================
|
||||
|
||||
Processing console (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/console/partitions.bin
|
||||
Retrieving maximum program size .pio/build/console/firmware.elf
|
||||
Checking size .pio/build/console/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [== ] 19.8% (used 64744 bytes from 327680 bytes)
|
||||
Flash: [==== ] 36.8% (used 1158621 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.86 seconds =========================
|
||||
|
||||
Environment Status Duration
|
||||
------------- -------- ------------
|
||||
bridge SUCCESS 00:00:00.863
|
||||
console SUCCESS 00:00:00.858
|
||||
========================= 2 succeeded in 00:00:01.721 =========================
|
||||
|
||||
== page size: src/web_page.h raw string ==
|
||||
page bytes: 48598 (a reflashed device must serve exactly this many; kIndexHtmlLen is sizeof(kIndexHtml)-1 of this same string)
|
||||
|
||||
== repo hygiene ==
|
||||
repo hygiene: OK (71 tracked files, no ignored-tracked files, no key-material shapes, no PII hits)
|
||||
|
||||
== hardware context (informational; cannot change the gate result) ==
|
||||
hw-probe serial /dev/ttyACM0 present, readable (NOT opened: opening toggles DTR/RTS and resets the board)
|
||||
hw-probe mdns keyrelay.local resolves -> 10.2.0.22
|
||||
hw-probe https https://keyrelay.local/ -> HTTP 200 (TLS listener is up)
|
||||
hw-probe http http://keyrelay.local/ -> HTTP 200, no redirect (plaintext page still served: the pre-phase-02 shape)
|
||||
hw-probe tls 10.2.0.22:443 negotiated TLSv1.2 / ECDHE-ECDSA-AES256-GCM-SHA384 (a self-signed verify failure is the expected shape; the fingerprint to compare it against is on the serial console)
|
||||
hw-probe uv /home/ducoterra/.local/bin/uv — firmware builds available
|
||||
hw-probe node /usr/bin/node — test_page.js runs
|
||||
hw-probe evdev board 046d:c33f visible: keyboard=/dev/input/event19 (readable) mouse=/dev/input/event20 (readable) — python3 tools/watch_target.py runs ON THIS machine (the target)
|
||||
validation OK (suites + sanitised suites + bridge/console builds + page size + hygiene)
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
**Task 04 (`02_tls_control_channel/04_transport_abstraction.md`) — complete.**
|
||||
|
||||
- `src/conn.h`: one `kr::Conn` transport view (tagged union, no virtual — rebinding per slot, inlinable pump) over `WiFiClient`/`tls::Session`; whole-frame-or-nothing `push`, resumable `pump` capped per write (4 KB) and per tick, flash body streamed through one 1460 B RAM chunk.
|
||||
- `:80` is now redirect-only via pure `plaintextRoute()`: `301 https://…`, `426 Upgrade Required` for a plaintext `/ws` upgrade **and** for any `?token=` request (a `Location` would leak the passphrase twice); full `301`/`426` body pair built by the one `renderHttpResponseHead()`. `serveReadonly()` is the single HTTP answer for both slots.
|
||||
- Safety invariant kept and pinned: `_lastInboundMs` is stamped only for `WebSocket && _authed` — handshake, `/status` and viewer frames cannot keep a dead controller armed.
|
||||
- Tests: new `tests/test_conn.cpp` (264 checks, 100 % of the pure half), `test_tls_session` 135→118 (`WriteQueue` deleted; `TxRing` reseat/unseated pinned), `test_relayctl` 160→189 (structural pins: one formatter, one route decision, one clock stamp, page bytes == `kIndexHtmlLen`), `test_page` 84→93 (`https:`→`wss://`, no credential in the connect URL).
|
||||
- Two real bugs found by the **sanitised** run and fixed, each pinned by the case that triggered it: `memcmp` past a short query, and `octets[4]` overflow on `"192.168.1.1.1"`.
|
||||
- Gate: `.agents/validate.sh` exits 0 — 4687 checks in both the normal and `SANITIZE=1` runs, `bridge` RAM 30.4 % (99 616)/Flash 39.5 % (1 242 329), `console` 20.5 %/37.0 %, page 48 598 B, hygiene OK.
|
||||
- Device (flashed, observed): `https://…/` = 48 598 B ×3 with `sha256` == `web_page.h`; `/`→301, `/index.html`→301, `/nope`→301 to `/`; `/status?token=`→426 with no token in the body; `/ws`→426 (`rejected=1` on the board); `wss://` upgrade→101, wrong passphrase→`E1`+close; viewer 200/401 concurrently; heap 140 k/109 k/182 k over 0–2 sessions.
|
||||
- Docs moved: README (intro count, quick start `https://`, security-model rewrite, measured-behaviour rows, architecture map +`conn.h`, tests table, gaps), AGENTS.md (`curl -sk`, 4687, new defaults), `.agents/HW_VERIFICATION.md` rows.
|
||||
- Not run, recorded honestly: the keystroke/silence rows need an *authenticated* controller and this board's passphrase is not the default (`dflt:0`) — I did not change a credential I could not restore.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
== host suites: bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
test_tls_session 118 checks, 0 failures
|
||||
test_conn 264 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
one routing path, two transports
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 189 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
the connect path
|
||||
element ids
|
||||
page 93 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== host suites: SANITIZE=1 bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
sanitizers: on
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
test_tls_session 118 checks, 0 failures
|
||||
test_conn 264 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
one routing path, two transports
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 189 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
the connect path
|
||||
element ids
|
||||
page 93 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== firmware: platformio run -e bridge -e console ==
|
||||
Processing bridge (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/bridge/partitions.bin
|
||||
Retrieving maximum program size .pio/build/bridge/firmware.elf
|
||||
Checking size .pio/build/bridge/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [=== ] 30.4% (used 99616 bytes from 327680 bytes)
|
||||
Flash: [==== ] 39.5% (used 1242329 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.88 seconds =========================
|
||||
|
||||
Processing console (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/console/partitions.bin
|
||||
Retrieving maximum program size .pio/build/console/firmware.elf
|
||||
Checking size .pio/build/console/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [== ] 20.5% (used 67224 bytes from 327680 bytes)
|
||||
Flash: [==== ] 37.0% (used 1162585 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.87 seconds =========================
|
||||
|
||||
Environment Status Duration
|
||||
------------- -------- ------------
|
||||
bridge SUCCESS 00:00:00.882
|
||||
console SUCCESS 00:00:00.866
|
||||
========================= 2 succeeded in 00:00:01.748 =========================
|
||||
|
||||
== page size: src/web_page.h raw string ==
|
||||
page bytes: 48598 (a reflashed device must serve exactly this many; kIndexHtmlLen is sizeof(kIndexHtml)-1 of this same string)
|
||||
|
||||
== repo hygiene ==
|
||||
repo hygiene: OK (71 tracked files, no ignored-tracked files, no key-material shapes, no PII hits)
|
||||
|
||||
== hardware context (informational; cannot change the gate result) ==
|
||||
hw-probe serial /dev/ttyACM0 present, readable (NOT opened: opening toggles DTR/RTS and resets the board)
|
||||
hw-probe mdns keyrelay.local resolves -> 10.2.0.22
|
||||
hw-probe https https://keyrelay.local/ -> HTTP 200 (TLS listener is up)
|
||||
hw-probe http http://keyrelay.local/ -> HTTP 301, redirects to https://keyrelay.local/ (redirect-only: the post-phase-02 shape)
|
||||
hw-probe tls 10.2.0.22:443 negotiated TLSv1.2 / ECDHE-ECDSA-AES256-GCM-SHA384 (a self-signed verify failure is the expected shape; the fingerprint to compare it against is on the serial console)
|
||||
hw-probe uv /home/ducoterra/.local/bin/uv — firmware builds available
|
||||
hw-probe node /usr/bin/node — test_page.js runs
|
||||
hw-probe evdev board 046d:c33f visible: keyboard=/dev/input/event19 (readable) mouse=/dev/input/event20 (readable) — python3 tools/watch_target.py runs ON THIS machine (the target)
|
||||
validation OK (suites + sanitised suites + bridge/console builds + page size + hygiene)
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
**Task 05 (`02_tls_control_channel/05_page_client_fingerprint.md`) — complete.**
|
||||
|
||||
- **Page** (`src/web_page.h`): one 19-byte `#if KR_TLS` build marker joins the raw-string chunks (branches equal length → page size stays one number); TLS page on an `http:` origin opens **no socket, sends no frame**, disables the passphrase box + connect button behind a banner ("this page arrived in the clear; reload over https") — never a silent `ws://` fallback; rollback build keeps `ws://`; new `tls`/`plaintext` pill and a certificate line rendered from the status frame's `fp` only (nothing when `tls:0` or no `fp`).
|
||||
- **`relayctl.py`**: TLS by default on :443 via stdlib `ssl`; `--fingerprint`/`$KEYRELAY_TLS_FP` hashes the peer DER and **aborts before any frame** on mismatch; `--ca` = `create_default_context` + hostname checking; `--insecure` warns on every run; none of them → refuses (exit 2) without a socket; `--plain` is the only, explicit path to :80; 426/301 messages updated (tool now has a TLS client). Token pre-flight, `paste --yes` gate, no token ever printed — kept.
|
||||
- **Tests**: `test_relayctl` 189→271 (trust-decision matrix, port table, fingerprint normalisation/refusals, fake-board byte recording proving mismatch ⇒ zero bytes sent, `--ca`/`--insecure`/`--plain` shapes, main-level refusals, page assembled from *both* marker branches); `test_page` 93→113 (http: refusal incl. `boot()` disabling inputs, rollback marker keeps `ws://`, pill + exact-`fp` rendering); `test_conn` count 264→268 + `kServedPageBytes` 51 310→**51 626**; `test_proto.cpp` untouched.
|
||||
- **Gate**: `bash .agents/validate.sh` → **validation OK** — 4793 checks in both normal and `SANITIZE=1` runs; bridge RAM 30.4 % (99 616) / Flash 39.6 % (1 245 353), console 20.5 %/37.1 %; page bytes 51 626; hygiene OK. Coverage of changed/added `relayctl.py` functions: **156/158 = 98.7 %** (stdlib `trace`). `ruff --select F,E9` clean on `tools/`+`tests/`; both marker branches compile (`KR_TLS=0/1` syntax-checked).
|
||||
- **Device** (flashed `bridge`, board healthy, not in download mode): served page **51 626 B**, sha256 `dd16e195…f04e9` byte-equal to the locally assembled TLS page, marker `=1`, new ids present; `:80` still 301. `--fingerprint 00…00` → `certificate fingerprint mismatch … Nothing was sent`; real pin / `--insecure` / `--ca <exported self-signed>` all passed their trust step and stopped at authentication (`E1` — the passphrase is the operator's, 3 authfails total, not guessed); no argument → exit 2, no socket; `--plain` → the 426 sentence, no passphrase blame. Recorded in `.agents/HW_VERIFICATION.md`; typing over a pinned session stays the operator's confirmation.
|
||||
- **Docs**: README (4793 counts, Quick start pinning block with `cert`/`curl -sk …/status?token=`/`$KEYRELAY_TLS_FP`, Controller-page byte count + 3 new element rows, architecture map, end-to-end examples, 2 new Troubleshooting rows incl. the wrong-network/identity-rotation wording in full, tests table), AGENTS.md (check count, page-size and raw-string statements now describe the marker, new cross-check table row), `.agents/validate.sh` page-size check now assembles chunks+marker (would otherwise fail on the new layout).
|
||||
- **Notable**: the page must differ per build (a runtime probe would *guess* whether the board does TLS — invariant 5), hence the equal-length build marker; the pin hash deliberately runs post-handshake on the presented DER so self-signed pinning needs no CA ceremony, while `--ca` keeps OpenSSL's full verification.
|
||||
- **Next pending task**: `02_tls_control_channel/06_tls_docs_rollback.md`.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
== host suites: bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
test_tls_session 118 checks, 0 failures
|
||||
test_conn 268 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
one routing path, two transports
|
||||
the client side of pinning
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 271 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
the connect path
|
||||
the channel pill and the certificate line
|
||||
element ids
|
||||
page 113 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== host suites: SANITIZE=1 bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
sanitizers: on
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
test_tls_session 118 checks, 0 failures
|
||||
test_conn 268 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
one routing path, two transports
|
||||
the client side of pinning
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 271 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
the connect path
|
||||
the channel pill and the certificate line
|
||||
element ids
|
||||
page 113 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== firmware: platformio run -e bridge -e console ==
|
||||
Processing bridge (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/bridge/partitions.bin
|
||||
Retrieving maximum program size .pio/build/bridge/firmware.elf
|
||||
Checking size .pio/build/bridge/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [=== ] 30.4% (used 99616 bytes from 327680 bytes)
|
||||
Flash: [==== ] 39.6% (used 1245353 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.86 seconds =========================
|
||||
|
||||
Processing console (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/console/partitions.bin
|
||||
Retrieving maximum program size .pio/build/console/firmware.elf
|
||||
Checking size .pio/build/console/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [== ] 20.5% (used 67224 bytes from 327680 bytes)
|
||||
Flash: [==== ] 37.1% (used 1165609 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.85 seconds =========================
|
||||
|
||||
Environment Status Duration
|
||||
------------- -------- ------------
|
||||
bridge SUCCESS 00:00:00.862
|
||||
console SUCCESS 00:00:00.854
|
||||
========================= 2 succeeded in 00:00:01.716 =========================
|
||||
|
||||
== page size: src/web_page.h raw strings ==
|
||||
page bytes: 51626 (a reflashed device must serve exactly this many; kIndexHtmlLen is sizeof(kIndexHtml)-1 of these same bytes, both builds)
|
||||
|
||||
== repo hygiene ==
|
||||
repo hygiene: OK (71 tracked files, no ignored-tracked files, no key-material shapes, no PII hits)
|
||||
|
||||
== hardware context (informational; cannot change the gate result) ==
|
||||
hw-probe serial /dev/ttyACM0 present, readable (NOT opened: opening toggles DTR/RTS and resets the board)
|
||||
hw-probe mdns keyrelay.local resolves -> 10.2.0.22
|
||||
hw-probe https https://keyrelay.local/ -> HTTP 200 (TLS listener is up)
|
||||
hw-probe http http://keyrelay.local/ -> HTTP 301, redirects to https://keyrelay.local/ (redirect-only: the post-phase-02 shape)
|
||||
hw-probe tls 10.2.0.22:443 negotiated TLSv1.2 / ECDHE-ECDSA-AES256-GCM-SHA384 (a self-signed verify failure is the expected shape; the fingerprint to compare it against is on the serial console)
|
||||
hw-probe uv /home/ducoterra/.local/bin/uv — firmware builds available
|
||||
hw-probe node /usr/bin/node — test_page.js runs
|
||||
hw-probe evdev board 046d:c33f visible: keyboard=/dev/input/event19 (readable) mouse=/dev/input/event20 (readable) — python3 tools/watch_target.py runs ON THIS machine (the target)
|
||||
validation OK (suites + sanitised suites + bridge/console builds + page size + hygiene)
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
**Implemented**
|
||||
- `platformio.ini`: new `[env:rollback]` (`extends env:bridge`, unflags `-DKR_TLS=1`, sets `-DKR_TLS=0`) — `pio run -e rollback` is now the documented, reproducible rollback; `pio run` has no `--build-flags`, so an env is the only unambiguous spelling.
|
||||
- `.agents/validate.sh`: builds all three envs, plus new check 5 that pins the docs to measurements — check count in README+AGENTS, **every Tests-table row against that suite's own line**, the page byte count, Backlog numbered 1..N, and every `ws://` line must name the rollback on the same line; fixed its stale `curl -s http://` comment.
|
||||
- README: TLS intro bullet; Safety model "TLS is transport, not an arming input"; trust table gains "who can see the traffic" (with the unpinned window stated) and "anyone with a copy of this firmware"; WiFi-owner row corrected; new "What TLS does not buy" + "the certificate you did not check is the one thing to check"; Wire-protocol transport paragraph + the non-`E<code>` refusals (401/503/301/**426**); new **"The rollback — building it, and what it costs"**; Measured-behaviour rows (footprint vs baseline, TLS cost, handshake time, session heap); Troubleshooting rollback row; 5 Design decisions (challenge–response, on-board identity, raw mbedTLS vs `esp_tls`, 426 vs 301, rollback-as-build); Backlog TLS item removed, renumbered 1–9, narrower "a certificate a browser already trusts" added.
|
||||
- Docstrings: "what it does NOT protect / must not reverse" added to `tls.h`, `tls_pem.h`, `tls_session.h`, `conn.h`, `relayctl.py`. AGENTS.md: corrected facts only (3-env gate, `conn.h` pure half, gate checks doc numbers, TLS identity defaults, "Three tables"→"Tables", "last row"→"evdev row").
|
||||
- Fixed earlier-task defects: stale `test_page | 93`→113; two Tests rows missing a closing pipe + a blank line splitting that table; HW_VERIFICATION duplicate blank `/ws` row and a heap row wrapped over 6 lines (broke its table).
|
||||
|
||||
**Tests/lint**: `bash .agents/validate.sh` → **exit 0, validation OK**; 4793 checks / 0 failures in both the plain and `SANITIZE=1` runs; page bytes 51 626; RAM/Flash — bridge 30.4 %/99 616 · 39.6 %/1 245 353, console 20.5 %/67 224 · 37.1 %/1 165 609, **rollback 28.5 %/93 456 · 36.4 %/1 146 137**; `ruff --select F,E9 tools/ tests/` clean; `bash -n` clean. No new executable code, so coverage is unchanged (pure modules already 100 %).
|
||||
|
||||
**Docs**: README.md and AGENTS.md updated as above.
|
||||
|
||||
**Deviations**: rollback proven by build + binary evidence, not by reflashing — `nm` gives 0 `mbedtls_ssl_*`, 0 `mbedtls_x509write`, 0 identity strings in the rollback image vs 115/15/1 in `bridge`; flashing the rollback and back would put a live HID keyboard into download mode on the host running this pipeline, so the device leg is recorded `skipped (not flashed)` in `.agents/HW_VERIFICATION.md` with the exact commands. Handshake time measured this task (0.349–0.423 s warm ×7, 3.94 s cold, page whole in 0.53–0.62 s); heap quoted from the recorded task 03/04 serial readouts, not re-measured (opening the CDC port resets the board).
|
||||
|
||||
**Next pending task**: this was phase 02's last task; after the harness moves it, next is `03_session_takeover/01_pending_claim_socket.md`.
|
||||
+1
@@ -0,0 +1 @@
|
||||
ok
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
== host suites: bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
test_tls_session 118 checks, 0 failures
|
||||
test_conn 268 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
one routing path, two transports
|
||||
the client side of pinning
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 271 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
the connect path
|
||||
the channel pill and the certificate line
|
||||
element ids
|
||||
page 113 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== host suites: SANITIZE=1 bash tests/run_tests.sh ==
|
||||
compiler: g++ inside localhost/ai-sandbox:ubuntu-9a08b1d500b0 (repo mounted at /work)
|
||||
sanitizers: on
|
||||
keystate 40 checks, 0 failures
|
||||
proto 2359 checks, 0 failures
|
||||
text 459 checks, 0 failures
|
||||
mouse 48 checks, 0 failures
|
||||
output 153 checks, 0 failures
|
||||
ws_codec 135 checks, 0 failures
|
||||
test_tls_pem 829 checks, 0 failures
|
||||
test_tls_session 118 checks, 0 failures
|
||||
test_conn 268 checks, 0 failures
|
||||
handshake
|
||||
frame encoding
|
||||
frame decoding
|
||||
key table
|
||||
pasted text
|
||||
mouse
|
||||
protocol strings
|
||||
the fail-safe wiring
|
||||
one routing path, two transports
|
||||
the client side of pinning
|
||||
the target-side verifier
|
||||
t= 0.00s >>> Ctrl+Alt+Del <<<
|
||||
relayctl 271 checks, 0 failures
|
||||
the log stays readable
|
||||
characters
|
||||
key names in the log
|
||||
sending text
|
||||
refusing what it cannot type
|
||||
stopping
|
||||
the mouse
|
||||
the connect path
|
||||
the channel pill and the certificate line
|
||||
element ids
|
||||
page 113 checks, 0 failures
|
||||
RESULT: all suites passed
|
||||
|
||||
== firmware: platformio run -e bridge -e console -e rollback ==
|
||||
Processing bridge (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/bridge/partitions.bin
|
||||
Retrieving maximum program size .pio/build/bridge/firmware.elf
|
||||
Checking size .pio/build/bridge/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [=== ] 30.4% (used 99616 bytes from 327680 bytes)
|
||||
Flash: [==== ] 39.6% (used 1245353 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.86 seconds =========================
|
||||
|
||||
Processing console (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/console/partitions.bin
|
||||
Retrieving maximum program size .pio/build/console/firmware.elf
|
||||
Checking size .pio/build/console/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [== ] 20.5% (used 67224 bytes from 327680 bytes)
|
||||
Flash: [==== ] 37.1% (used 1165609 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.86 seconds =========================
|
||||
|
||||
Processing rollback (platform: espressif32@8.0.0; board: esp32-s3-devkitc-1; framework: arduino)
|
||||
--------------------------------------------------------------------------------
|
||||
Verbose mode can be enabled via `-v, --verbose` option
|
||||
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32-s3-devkitc-1.html
|
||||
PLATFORM: Espressif 32 (8.0.0) > Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)
|
||||
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
|
||||
DEBUG: Current (esp-builtin) On-board (esp-builtin) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
|
||||
PACKAGES:
|
||||
- framework-arduinoespressif32 @ 4.30312.261024 (3.3.12)
|
||||
- framework-arduinoespressif32-esp32s3-libs @ 3.3.12
|
||||
- tool-esptool @ 2.50400.0 (5.4.0)
|
||||
- tool-riscv32-esp-elf-gdb @ 12.1.0+20221002
|
||||
- tool-xtensa-esp-elf-gdb @ 12.1.0+20221002
|
||||
- toolchain-riscv32-esp @ 14.2.0+20260121
|
||||
- toolchain-xtensa-esp-elf @ 14.2.0+20260121
|
||||
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
|
||||
LDF Modes: Finder ~ chain, Compatibility ~ soft
|
||||
Found 45 compatible libraries
|
||||
Scanning dependencies...
|
||||
Dependency Graph
|
||||
|-- Adafruit NeoPixel @ 1.15.5
|
||||
|-- ESPmDNS @ 3.3.12
|
||||
|-- USB @ 3.3.12
|
||||
|-- Preferences @ 3.3.12
|
||||
|-- WiFi @ 3.3.12
|
||||
Building in release mode
|
||||
Generating partitions .pio/build/rollback/partitions.bin
|
||||
Retrieving maximum program size .pio/build/rollback/firmware.elf
|
||||
Checking size .pio/build/rollback/firmware.elf
|
||||
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
|
||||
RAM: [=== ] 28.5% (used 93456 bytes from 327680 bytes)
|
||||
Flash: [==== ] 36.4% (used 1146137 bytes from 3145728 bytes)
|
||||
========================= [SUCCESS] Took 0.87 seconds =========================
|
||||
|
||||
Environment Status Duration
|
||||
------------- -------- ------------
|
||||
bridge SUCCESS 00:00:00.862
|
||||
console SUCCESS 00:00:00.860
|
||||
rollback SUCCESS 00:00:00.867
|
||||
========================= 3 succeeded in 00:00:02.589 =========================
|
||||
|
||||
== page size: src/web_page.h raw strings ==
|
||||
page bytes: 51626 (a reflashed device must serve exactly this many; kIndexHtmlLen is sizeof(kIndexHtml)-1 of these same bytes, both builds)
|
||||
|
||||
== README/AGENTS claims vs what this run measured ==
|
||||
README/AGENTS claims: OK (4 793 checks quoted and measured in both runs; 11 Tests-table rows match their suites; 51 626 page bytes quoted; Backlog contiguous; every ws:// sentence names the rollback)
|
||||
|
||||
== repo hygiene ==
|
||||
repo hygiene: OK (71 tracked files, no ignored-tracked files, no key-material shapes, no PII hits)
|
||||
|
||||
== hardware context (informational; cannot change the gate result) ==
|
||||
hw-probe serial /dev/ttyACM0 present, readable (NOT opened: opening toggles DTR/RTS and resets the board)
|
||||
hw-probe mdns keyrelay.local resolves -> 10.2.0.22
|
||||
hw-probe https https://keyrelay.local/ -> HTTP 200 (TLS listener is up)
|
||||
hw-probe http http://keyrelay.local/ -> HTTP 301, redirects to https://keyrelay.local/ (redirect-only: the post-phase-02 shape)
|
||||
hw-probe tls 10.2.0.22:443 negotiated TLSv1.2 / ECDHE-ECDSA-AES256-GCM-SHA384 (a self-signed verify failure is the expected shape; the fingerprint to compare it against is on the serial console)
|
||||
hw-probe uv /home/ducoterra/.local/bin/uv — firmware builds available
|
||||
hw-probe node /usr/bin/node — test_page.js runs
|
||||
hw-probe evdev board 046d:c33f visible: keyboard=/dev/input/event19 (readable) mouse=/dev/input/event20 (readable) — python3 tools/watch_target.py runs ON THIS machine (the target)
|
||||
validation OK (suites + sanitised suites + bridge/console/rollback builds + page size
|
||||
+ the numbers README/AGENTS quote + hygiene)
|
||||
Reference in New Issue
Block a user