diff options
Diffstat (limited to 'RELAY_HARDENING_PLAN.md')
| -rw-r--r-- | RELAY_HARDENING_PLAN.md | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/RELAY_HARDENING_PLAN.md b/RELAY_HARDENING_PLAN.md new file mode 100644 index 0000000..7b726cc --- /dev/null +++ b/RELAY_HARDENING_PLAN.md | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | # Relay Hardening + Remaining Work — Implementation Plan | ||
| 2 | |||
| 3 | ## Overview | ||
| 4 | |||
| 5 | Post-merge cleanup and remaining work on the `feature/relay-hardening` branch. Covers CVM+relay integration tests, test infrastructure polish, documentation updates, display testing, cross-board payment, OpenWRT interop, and NIP-77 negentropy adapter. | ||
| 6 | |||
| 7 | **Branch:** `feature/relay-hardening` (from `master` at `81f2dc5`) | ||
| 8 | **Worktree:** `/home/c03rad0r/esp32-tollgate-hardening` | ||
| 9 | **Main repo:** `/home/c03rad0r/esp32-tollgate` | ||
| 10 | |||
| 11 | --- | ||
| 12 | |||
| 13 | ## Checklist | ||
| 14 | |||
| 15 | ### Phase 1: CVM + Relay Integration (Group A) | ||
| 16 | |||
| 17 | - [ ] Write `tests/integration/test-cvm-relay.mjs` — CVM tool call via local relay (ws://BOARD_IP:4869) | ||
| 18 | - Connect WS to local relay | ||
| 19 | - Subscribe to kind 25910 for board's npub | ||
| 20 | - Verify CEP-6 announcements (kind 11316/11317/10002) stored in local relay | ||
| 21 | - Publish kind 25910 MCP request via local relay | ||
| 22 | - Verify response received via local relay | ||
| 23 | - [ ] Add `test-cvm-relay` make target to main `Makefile` (with board lock) | ||
| 24 | - [ ] Add `test-cvm-relay` make target to `physical-router-test-automation/esp32/Makefile` (with board lock) | ||
| 25 | - [ ] Add passthrough target to top-level `physical-router-test-automation/Makefile` | ||
| 26 | - [ ] End-to-end MCP tools/call roundtrip via kind 25910 on public relay | ||
| 27 | - Extend existing `cvm-test-tool` or write new test | ||
| 28 | - Publish kind 25910 to public relay, verify response on public relay | ||
| 29 | - Test at least `get_config` and `get_balance` | ||
| 30 | - [ ] Add `test-cvm-e2e` make target to main `Makefile` (with board lock) | ||
| 31 | - [ ] Verify board npub on contextvm.org/servers (manual check, document result) | ||
| 32 | - [ ] Add `test-cvm-e2e` make target to `physical-router-test-automation/esp32/Makefile` | ||
| 33 | - [ ] Flash firmware with relay to Board B, lock board, run all CVM+relay tests | ||
| 34 | |||
| 35 | ### Phase 2: Test Infrastructure Cleanup (Group B) | ||
| 36 | |||
| 37 | - [x] IP fallbacks already correct (all tests use `process.env.TOLLGATE_IP || '10.192.45.1'`, no `192.168.4.1`) | ||
| 38 | - [x] Test directories already at correct paths (`tests/integration/`, `tests/e2e/`) | ||
| 39 | - [x] Integration tests already in `tests/integration/` (api, network, phase2, smoke, test-cvm, test-reset-auth, test-session-expiry, test-dns-firewall, test-local-relay, test-relay-nip11) | ||
| 40 | - [x] E2E tests already in `tests/e2e/` (captive-portal.spec, interop-happy-path.spec) | ||
| 41 | - [ ] Add `test-local-relay` and `test-relay-nip11` targets to main `Makefile` (with board lock) | ||
| 42 | - [ ] Add `smoke` make target alias to `physical-router-test-automation/esp32/Makefile` for relay firmware | ||
| 43 | - [ ] Per-test context isolation in `tests/e2e/playwright.config.mjs` | ||
| 44 | - [ ] Verify Playwright `.webm` video recording in `tests/e2e/test-results/` | ||
| 45 | - [ ] Run full integration test suite on Board B to verify nothing regressed | ||
| 46 | |||
| 47 | ### Phase 3: Documentation (Group C) | ||
| 48 | |||
| 49 | - [ ] Update AGENTS.md: firewall description → "per-client NAT filter via LWIP_HOOK_IP4_CANFORWARD" | ||
| 50 | - [ ] Update AGENTS.md: session.c description → remove "spent-secret tracking" | ||
| 51 | - [ ] Update AGENTS.md: add display module docs (display.c/h, font.c/h, QR cycling, states) | ||
| 52 | - [ ] Update AGENTS.md: add relay hardening make targets to test instructions | ||
| 53 | - [ ] Verify CVM announcements on relay.primal.net (Board B with internet) | ||
| 54 | - Kind 11316 server announcement | ||
| 55 | - Kind 11317 tools list | ||
| 56 | - Kind 10002 relay list | ||
| 57 | - [ ] Update CHECKLIST.md: mark verified items, add relay-hardening items | ||
| 58 | |||
| 59 | ### Phase 4: Display Testing on Board C (Group D.1) | ||
| 60 | |||
| 61 | - [ ] Add unit test for `escape_wifi_field()` in `tests/unit/test_display.c` | ||
| 62 | - Test: no special chars → no escaping | ||
| 63 | - Test: semicolons, colons, backslashes, commas, quotes → backslash-escaped | ||
| 64 | - Test: multiple special chars in one string | ||
| 65 | - Test: empty string | ||
| 66 | - [ ] Add unit test for QR matrix generation in `tests/unit/test_display.c` | ||
| 67 | - Test: valid QR matrix for various string lengths | ||
| 68 | - Test: WIFI: URI format correctness | ||
| 69 | - [ ] Update `tests/unit/Makefile` with `test_display` target | ||
| 70 | - [ ] Lock Board C (`make lock-c PHASE="display testing"`) | ||
| 71 | - [ ] Flash firmware to Board C at `/dev/ttyACM3` | ||
| 72 | - [ ] Verify boot screen shows "TollGate starting..." | ||
| 73 | - [ ] Verify QR code renders on display | ||
| 74 | - [ ] Verify Wi-Fi QR is scannable by Android/iOS camera | ||
| 75 | - [ ] Verify portal URL QR is scannable and loads captive portal | ||
| 76 | - [ ] Verify QR cycling (Wi-Fi ↔ Portal URL every 5s) | ||
| 77 | - [ ] Unlock Board C | ||
| 78 | |||
| 79 | ### Phase 5: Board B Config + Cross-Board Payment (Group D.2) | ||
| 80 | |||
| 81 | - [ ] Create Board B `config.json` with unique nsec (`9af47906b45aca5e238390f3d03c8274e154198e81aa2095065627d1e61ca968`) | ||
| 82 | - Derived identity: SSID `TollGate-b96d80`, AP IP `10.185.47.1`, AP MAC `fe:08:f7:b9:6d:80` | ||
| 83 | - [ ] Lock Board B (`make lock-b PHASE="Board B config + cross-board test"`) | ||
| 84 | - [ ] Flash Board B with new config | ||
| 85 | - [ ] Verify Board B boots with different SSID/IP from Board A | ||
| 86 | - [ ] Connect laptop to Board B, verify captive portal works | ||
| 87 | - [ ] Cross-board payment test: Board B pays Board A (Scenario 5) | ||
| 88 | - Board B as STA connects to Board A's AP | ||
| 89 | - Board B auto-detects Board A as upstream TollGate (kind 10021) | ||
| 90 | - Board B wallet creates token, POSTs to Board A | ||
| 91 | - Verify Board B gets internet through Board A | ||
| 92 | - [ ] Write integration test `tests/integration/test-cross-board.mjs` | ||
| 93 | - [ ] Add `test-cross-board` make target to main `Makefile` and physical-router-test-automation | ||
| 94 | - [ ] Unlock Board B | ||
| 95 | |||
| 96 | ### Phase 6: OpenWRT Interop (Group D.3) | ||
| 97 | |||
| 98 | - [ ] SSH to `root@10.47.41.1`, verify `tollgate-wrt` still running | ||
| 99 | - [ ] Test `curl http://10.47.41.1:2121/` — verify kind=10021 response | ||
| 100 | - [ ] Investigate `nofee.testnut.cashu.space` API compatibility | ||
| 101 | - [ ] Document findings in CHECKLIST.md or OpenWRT interop notes | ||
| 102 | |||
| 103 | ### Phase 7: NIP-77 Negentropy Adapter (Group D.4) | ||
| 104 | |||
| 105 | - [ ] Write `main/negentropy_storage.c/h` — adapter from wisp storage to negentropy API | ||
| 106 | - `negentropy_storage_init()` — wrap storage_engine event iterator | ||
| 107 | - `negentropy_get_items()` — iterate stored events, return (timestamp, event_id) pairs | ||
| 108 | - `negentropy_insert_items()` — insert reconciled events from remote | ||
| 109 | - [ ] Modify `sync_manager.c` — add negentropy sync path alongside REQ-diff | ||
| 110 | - Detect NIP-77 support from relay_selector (NIP-77 flag) | ||
| 111 | - If primary supports NIP-77: use NEG_OPEN/NEG_MSG instead of REQ-diff | ||
| 112 | - If primary doesn't support NIP-77: fall back to REQ-diff | ||
| 113 | - [ ] Add `tests/unit/test_negentropy_storage.c` — unit test with mock ID sets | ||
| 114 | - [ ] Update `tests/unit/Makefile` with `test_negentropy_storage` target | ||
| 115 | - [ ] Flash to Board B, verify sync with NIP-77 capable relay (orangesync) | ||
| 116 | |||
| 117 | --- | ||
| 118 | |||
| 119 | ## Hardware Access Rules | ||
| 120 | |||
| 121 | **ALWAYS acquire board lock before any hardware access:** | ||
| 122 | ```bash | ||
| 123 | # In physical-router-test-automation/esp32/ | ||
| 124 | make lock-b PHASE="relay integration testing" | ||
| 125 | make lock-c PHASE="display testing" | ||
| 126 | |||
| 127 | # Or via main repo | ||
| 128 | make lock-b PHASE="cross-board payment test" | ||
| 129 | ``` | ||
| 130 | |||
| 131 | **Make targets that touch hardware MUST use board locks:** | ||
| 132 | - All `flash-*` targets | ||
| 133 | - All `test-*` targets that run against live boards | ||
| 134 | - All `monitor-*` targets | ||
| 135 | |||
| 136 | **Make targets that DON'T need locks:** | ||
| 137 | - `test-unit` (host-only, no hardware) | ||
| 138 | - `build` (compile only) | ||
| 139 | - `cvm-pubkey` (read-only query) | ||
| 140 | |||
| 141 | **Always release lock when done:** | ||
| 142 | ```bash | ||
| 143 | make unlock-b | ||
| 144 | make unlock-c | ||
| 145 | ``` | ||
| 146 | |||
| 147 | ## Board Reference | ||
| 148 | |||
| 149 | | Board | Port | Factory MAC | SSID | AP IP | nsec | Use | | ||
| 150 | |-------|------|-------------|------|-------|------|-----| | ||
| 151 | | A | `/dev/ttyACM0` | `94:a9:90:2e:37:7c` | `TollGate-B96D80` | `10.185.47.1` | `9af47906...` | Primary test (WiFi broken) | | ||
| 152 | | B | `/dev/ttyACM1` | `fc:01:2c:c5:50:50` | `TollGate-C0E9CA` | `10.192.45.1` | default | Relay + CVM testing | | ||
| 153 | | C | `/dev/ttyACM3` | `20:6e:f1:98:d7:08` | TBD | TBD | TBD | Display testing | | ||
| 154 | |||
| 155 | ## Test Execution Order | ||
| 156 | |||
| 157 | 1. **No hardware needed:** `make test-unit` — verify all unit tests pass | ||
| 158 | 2. **Board B (lock required):** `make lock-b` → flash → CVM+relay tests → cross-board → `make unlock-b` | ||
| 159 | 3. **Board C (lock required):** `make lock-c` → flash → display tests → `make unlock-c` | ||
| 160 | 4. **No hardware:** documentation updates, AGENTS.md, CHECKLIST.md | ||
| 161 | 5. **OpenWRT (separate):** SSH checks, no board lock needed | ||
| 162 | |||
| 163 | ## Commit Strategy | ||
| 164 | |||
| 165 | - Commit + push after each phase completes | ||
| 166 | - Commit + push every time a test passes that previously didn't pass | ||
| 167 | - Squash into single commit before merging back to master | ||