diff --git a/docs/test-results/esp32_management_password_2026-10-19.json b/docs/test-results/esp32_management_password_2026-10-19.json new file mode 100644 index 000000000..b1e96cc89 --- /dev/null +++ b/docs/test-results/esp32_management_password_2026-10-19.json @@ -0,0 +1,146 @@ +{ + "schema_version": 1, + "date_utc": "2026-10-19", + "site": "Mercerwood mesh Pi", + "board": "XIAO S3 WIO", + "environment": "Xiao_S3_WIO_companion_radio_full", + "source_commit": "036fb47717774a1fb13e824175462ad4442d00c7", + "candidate": { + "version": "v1.18.0.1-halo-keymind-cascade-dev-036fb477", + "application_bytes": 2271096, + "application_sha256": "2419a991b7421b8444b0f39e4e941a60f9d4e5bcfb3a187ca77a0a2d41d31dcf" + }, + "baseline": { + "version": "v1.18.0.1-halo-keymind-cascade-dev-652289ee", + "flash_bytes": 8388608, + "full_flash_sha256": "9517ff0caa61ae5ae2be95d4dfd2ab28a58e979eb1c7607b857055b9fb5f1445", + "contacts": 350, + "channel_slots": 40, + "core_error_flags": 0 + }, + "physical_password_classes": [ + { + "ascii_bytes": 8, + "ap_security": "WPA2", + "actual_association": "PASS" + }, + { + "ascii_bytes": 15, + "contains_internal_space_and_punctuation": true, + "setter": "HTTP API", + "ap_security": "WPA2", + "actual_association": "PASS" + }, + { + "ascii_bytes": 5, + "setter": "HTTP API", + "ap_security": "open", + "actual_association": "PASS", + "admin_HTTP_authentication_still_required": true + }, + { + "ascii_bytes": 12, + "setter": "HTTP API", + "ap_security": "WPA2", + "actual_association": "PASS" + }, + { + "ascii_bytes": 12, + "setter": "production browser form", + "ap_security": "WPA2", + "actual_association": "PASS" + } + ], + "HTTP_sessions": { + "old_cookie_general_config_status": 401, + "old_cookie_other_request_receipt_status": 401, + "originating_scoped_receipt": "PASS", + "old_password_login_status": 401, + "new_password_login_status": 200, + "warm_software_reboot_persistence": "PASS" + }, + "production_browser": { + "result": "PASS", + "normal_homepage_loader": true, + "native_fetch_unchanged": true, + "production_handlers_unchanged": true, + "password_save_posts": 1, + "new_password_login_posts": 1, + "automatic_reauthentication": true, + "actual_AP_rejoin": true, + "owned_browser_cleanup": true, + "decoded_loader_sha256": "4c58cc49a845b9080dca024a5143ebf99fdbb800f5a38a5d6c433e5f81a1a2e1", + "decoded_UI_sha256": "0b2b7a4d465cf0477af8cc72467bcc7333da8ac4aaeb46751749a2a3cf36c35b" + }, + "WiFi_OTA": { + "result": "PASS", + "protocol": "raw application binary with Content-Length", + "HTTP_Basic_username": "admin", + "same_admin_password_for_protected_AP_and_HTTP": true, + "GET_routes": [ + "/", + "/update", + "/log" + ], + "anonymous_wrong_and_old_credential_GET_status": 401, + "current_page_and_update_GET_status": 200, + "current_log_GET_status": 404, + "authenticated_packet_log_present": false, + "anonymous_empty_POST_status": 401, + "current_empty_POST_status": 400, + "image_upload_attempts": 1, + "streamed_bytes": 2271096, + "install_HTTP_status": 200, + "exact_install_success_body": true, + "postboot_USB_full_version_and_public_identity": "PASS", + "postboot_contacts": 350, + "postboot_channel_slots": 40, + "postboot_core_error_flags": 0, + "postboot_actual_AP_association_and_HTTP_login": "PASS", + "original_active_slot": "0x10000", + "CRC_selected_slot_after_OTA": "0x340000", + "alternate_slot_application_SHA256_readback": "PASS" + }, + "restoration": { + "result": "PASS", + "scope": "original app0, app1, NVS, SPIFFS and OTA metadata", + "all_partition_readbacks_verified": true, + "independent_full_flash_readback_bytes": 8388608, + "independent_full_flash_readback_sha256": "9517ff0caa61ae5ae2be95d4dfd2ab28a58e979eb1c7607b857055b9fb5f1445", + "byte_exact_to_baseline_before_runtime_handoff": true, + "partition_table_unchanged": true, + "bootloader_and_coredump_unchanged": true, + "original_OTA_metadata_restored": true, + "postboot_original_full_version_verified": true, + "postboot_stable_protocol_state_comparisons": { + "channels": true, + "contacts": true, + "device_info": true, + "full_cli_version": true, + "self_info": true + }, + "postboot_contacts": 350, + "postboot_channel_slots": 40, + "postboot_core_error_flags": 0, + "host_network": { + "original_wlan_restored": true, + "owned_profiles_removed": 12, + "ethernet_default_unchanged": true + } + }, + "limits": [ + "One physical ESP32 Full Companion board only", + "No physical qualification of infrastructure roles or other ESP32 families", + "No cold power-removal or uninterrupted WiFi soak qualification", + "Scripted raw OTA does not qualify the browser firmware uploader", + "No partition migration, interrupted upload or two-source recovery-AP throttle qualification" + ], + "failed_sample_notes": [ + "Initial incorrect test-manifest identity offset was caught before HTTP mutation", + "Initial Chromium startup deadline and direct UI-asset 409 were not counted as browser passes", + "A pre-browser HTTP transport failure recovered after an AP scan and guarded rejoin", + "Old WiFi key did not associate within 20 seconds; NetworkManager timeout is not a definitive wrong-key rejection" + ], + "result": "PASS", + "completed_utc": "2026-10-19T08:32:12.048555+00:00" +} diff --git a/docs/test-results/esp32_management_password_2026-10-19.md b/docs/test-results/esp32_management_password_2026-10-19.md new file mode 100644 index 000000000..0c77b7f93 --- /dev/null +++ b/docs/test-results/esp32_management_password_2026-10-19.md @@ -0,0 +1,112 @@ + +
+ + +# ESP32 management password hardware check, 2026-10-19 + +**PASS on one physical XIAO S3 WIO Full Companion at Mercerwood.** The same +admin password worked for the setup and OTA WiFi hotspots, WebConfig login, +and authenticated WiFi firmware upload at source `036fb477`. Password changes +through the production browser, automatic reauthentication, and persistence +after reboot and OTA passed. The original firmware/data and the Pi's networking +were restored and verified. This does not qualify every ESP32 board, firmware +role, migration path, or the release. + +A [sanitized result record](esp32_management_password_2026-10-19.json) preserves +the source/artifact hashes and check outcomes without credentials or device IDs. + +## Candidate and recovery baseline + +| Item | Recorded value | +| --- | --- | +| Physical board | XIAO S3 WIO | +| Firmware target | `Xiao_S3_WIO_companion_radio_full` | +| Source | [`036fb47717774a1fb13e824175462ad4442d00c7`](https://github.com/mikecarper/MeshCore/commit/036fb47717774a1fb13e824175462ad4442d00c7) | +| Candidate version | `v1.18.0.1-halo-keymind-cascade-dev-036fb477` | +| Application BIN size | 2,271,096 bytes | +| Application BIN SHA-256 | `2419a991b7421b8444b0f39e4e941a60f9d4e5bcfb3a187ca77a0a2d41d31dcf` | +| Pretrial full-flash backup size | 8,388,608 bytes | +| Pretrial full-flash backup SHA-256 | `9517ff0caa61ae5ae2be95d4dfd2ab28a58e979eb1c7607b857055b9fb5f1445` | + +The pretrial full-flash image and raw hardware evidence remain private. The +independent restoration readback matched this full-flash hash before runtime +handoff. Candidate application and full-flash backup hashes identify different +artifacts. + +## Physical results + +| Check | Observed result | +| --- | --- | +| Eight-character printable ASCII password | WPA-protected setup AP was usable with the admin password. | +| Fifteen-character ASCII password containing spaces and punctuation, saved through the API | Protected AP operation passed with the changed credential. | +| Five-character password | Setup AP became open; configuration still required the admin HTTP login. | +| Return to a twelve-character printable ASCII password | Protected AP operation passed again. | +| Session rotation | Old HTTP cookies were rejected; the originating operation retained its scoped save receipt. | +| Warm reboot persistence | The new password remained usable after an actual Binary Companion reboot. | +| Production browser password form | Login, exactly one password save, scoped receipt, automatic reauthentication, and actual protected-AP rejoin passed with the new password. | +| OTA hotspot and HTTP authentication | The same current admin password joined the protected OTA AP and authorized HTTP Basic as username `admin`. Anonymous, wrong and previous credentials returned HTTP 401 on `/`, `/update` and `/log`. | +| Empty OTA requests | Anonymous POST returned HTTP 401; authenticated empty POST returned HTTP 400 before image installation. | +| Real WiFi application upload | One raw application upload sent exactly 2,271,096 pinned bytes; HTTP 200 and the exact install/reboot response were received. | +| Post-OTA USB | Candidate full version and public identity matched; 350 contacts, 40 channel slots and zero core error flags were retained. | +| Post-OTA password persistence | The browser-saved password joined the protected setup AP and authenticated WebConfig after OTA; the previous password returned HTTP 401. | +| Alternate OTA slot | CRC-selected slot changed from original `app0` at `0x10000` to `app1` at `0x340000`; its application bytes matched the candidate SHA-256. | + +These are real-board association, HTTP API and production browser password +results. Chromium used the normal home-page loader and the decoded loader/UI +bodies matched the candidate's embedded hashes; native fetch and production +handlers were unchanged. One new-password login was observed, and the browser +was closed after success. This does not establish browser firmware-upload +completion behavior. The reboot was a software warm reboot; it does not +establish power-removal persistence or a battery-only cold start. + +The expected policy is documented in [WiFi setup](../WiFi.md), +[Full Companion](../companion_radio_full.md), and the +[password command](../cli_commands.md#view-or-change-this-nodes-admin-password). +Password classes are recorded here without exposing the test secrets, +network names, BSSIDs, cookies, or private device identity. + +## Original device and host state restored + +The original full `app0` and `app1` partitions, NVS and SPIFFS were restored, +with complete readback verification after every write. Original OTA metadata +was restored last. Bootloader, partition table and coredump bytes were unchanged. +An independent 8,388,608-byte readback then matched every byte and the SHA-256 of +the fresh pretrial backup, before the firmware was started again. + +The separate normal-boot check passed on the original `652289ee` build: +complete SELF_INFO and DEVICE_INFO records, full CLI version, all 350 raw contact +records, and canonical contents of all 40 channel slots matched the baseline. +Core error flags were zero and the USB session closed normally. Whole-flash +equality is a preboot observation; normal firmware may write flash after boot. + +The Pi's original WLAN profile was restored by its recorded UUID. All 12 owned +temporary profiles were removed. The original Ethernet connection, default +routes and selected Internet route remained unchanged. No factory reset or +bootloader/partition-table/coredump write was used. + +The same candidate version was used for the initial USB installation and the +WiFi upload. Installation is established by the success response and the +independent alternate-slot application readback, rather than by a version +string alone. The authenticated `/log` request returned HTTP 404 because no +packet log was present; unauthenticated access was rejected before that check. + +## Retained failed samples and limits + +Early attempts did not count as passes. An incorrect identity offset in the +test manifest was rejected before HTTP mutation. The first browser attempts +hit a startup deadline or requested the versioned UI asset without its required +version token; the completed browser run used the normal production loader. +A separate initial HTTP connection failed before browser startup; a fresh AP +scan and guarded rejoin restored access. + +A previous WiFi key did not associate within the 20-second wait, but +NetworkManager reported a timeout rather than the test's expected wrong-key +error. That sample establishes only bounded non-association. The HTTP old-key +rejections and successful new-key associations above are separate observations. +This campaign does not establish uninterrupted WiFi operation or cold-boot +behavior. + +A scripted raw upload does not by itself qualify the unchanged browser +uploader. The broader [ESP32 browser OTA release gates](hardware_validation_checklist.md#esp32-web-console-and-browser-ota-release-gates) +remain separate, as do two-source recovery-AP login throttling, infrastructure +roles, partition migration, and other hardware families. diff --git a/docs/test-results/hardware_validation_checklist.md b/docs/test-results/hardware_validation_checklist.md index d1d77137a..685a3e0b5 100644 --- a/docs/test-results/hardware_validation_checklist.md +++ b/docs/test-results/hardware_validation_checklist.md @@ -191,6 +191,15 @@ The [2026-10-05 V4/XIAO checkpoint](hardware_validation_esp32_web_console_ota_20 records reproduced browser OTA failures, fixes, physical results, and remaining USB qualification limits. It is not a release approval. +The [19 October XIAO S3 WIO password campaign](esp32_management_password_2026-10-19.md) +records Full Companion AP/password transitions, HTTP session rotation, +production browser password saves, warm-reboot persistence and a real +authenticated raw WiFi upload at `036fb477`. Post-OTA password persistence, +alternate-slot image readback, original device state and host networking all +passed. This scoped result does not close the browser-upload gate below, +two-source recovery-AP throttling, migration checks, or other board/role +qualification. + Host tests cannot prove USB enumeration, WiFi discovery, or an HTTP upload on the physical board. Before qualifying an ESP32 release, record the following on each available hardware family. Mark unavailable hardware as untested; a diff --git a/docs/test-results/hardware_validation_mercerwood_1_18_0_1_2026-10-18.md b/docs/test-results/hardware_validation_mercerwood_1_18_0_1_2026-10-18.md index 462a07634..1063f1e0b 100644 --- a/docs/test-results/hardware_validation_mercerwood_1_18_0_1_2026-10-18.md +++ b/docs/test-results/hardware_validation_mercerwood_1_18_0_1_2026-10-18.md @@ -581,6 +581,13 @@ Documentation route/link checks also passed in the CI-pinned renderer environmen authentication and browser cases. Execute migration credentials and both source OTA slots, actual browser upload, interruption/recovery, privileged replay persistence and transient guest churn. +- Retain the [19 October XIAO S3 WIO password results](esp32_management_password_2026-10-19.md): + AP/password transitions, session rotation, the production browser password + form, warm-reboot and post-OTA persistence, and a real authenticated raw WiFi + upload passed at `036fb477`. Alternate-slot image readback and exact original + flash/runtime state plus host networking restoration also passed. This scoped + Full Companion result leaves the broader authentication and browser OTA + gates above open. - Execute contact-storage fault cases, LoRa full/delta OTA and SD recovery. - Complete Indicator external WiFi/BLE endpoint, font, NTP and visible-rendering checks beyond the passed LoRa mode/boot-state cycle. Resolve the ESP-NOW Full diff --git a/docs/test-results/index.md b/docs/test-results/index.md index fb3aa35da..e39a1986a 100644 --- a/docs/test-results/index.md +++ b/docs/test-results/index.md @@ -43,6 +43,7 @@ Completed validation reports, experiments, and test guides are collected here. O ## Companion, USB, BLE, and display +- [ESP32 management password hardware check, 2026-10-19](esp32_management_password_2026-10-19.md) - [Companion lost-status replies](companion_lost_reply.md) - [Sensor dog tracker checks](sensor_dog_tracker.md) - [Contact-cache and NimBLE RAM qualification](companion_contact_cache_results.md)