Wave 9 #122.d.iii — Phase 6 Tailscale self-test (Gate E 'tunnel works both ways') - #121
Open
bernardc6 wants to merge 1 commit into
Open
Wave 9 #122.d.iii — Phase 6 Tailscale self-test (Gate E 'tunnel works both ways')#121bernardc6 wants to merge 1 commit into
bernardc6 wants to merge 1 commit into
Conversation
…el → phone → tunnel → HA) User-facing: Lets me confirm with one tap that I can reach my van from anywhere — and tells me honestly if the tunnel isn't working both ways. Context This slice lands the Gate E 'tunnel works both ways' sub-slice of the Phase 6 Tailscale wizard (Wave 9 #122.d.iii). The previous slice #122.a (commit 5f94405, PR #108) wired Path A (Tailscale) end-to-end + shipped Path B/C/D as stubs; this slice adds a one-tap self-test that proves the tunnel really works in both directions — not just that the dashboard loads (a stale one-way tunnel can still serve a cached page, which is the failure mode this slice catches). Two probes (outbound HTTPS via magicdns + inbound nonce POST) plus a round-trip nonce comparison tell the operator honestly whether their van is reachable from anywhere. Per the doctrine ('must not fail + super intuitive + critical infrastructure'): the probes have 10-second timeouts so a stalled tunnel never blocks the dashboard; the recovery automation fires after 60s and surfaces a plain-English notification instead of dropping the operator into a manual recovery; the §8.T.3 wizard- advance automation only fires when the global setup stage is at 'networking' (idempotent — no-ops if the parent wizard already advanced it). Changes NEW (4 files): - homeassistant/packages/roamcore_tailscale_self_test.yaml Inputs (tunnel URL password-mode + running flag + Run now button + last_run stamp), 2 shell_command probes (10s timeout each), 3 command_line sensors (HTTP code + expected/received nonce files), 4 template binary_sensors (outbound_ok / inbound_ok / ok / recovery), 1 template sensor (status — 6 plain-English branches, zero jargon), 3 §8 MANDATORY automations: §8.T.1 run (button + stage + event triggers, 30s settle, no URL clear), §8.T.2 recovery (60s timeout, persistent_notification, no URL clear), §8.T.3 wizard advance (only fires when rc_setup_stage == networking, flips to 'map', idempotent). - homeassistant/packages/tests/test_tailscale_self_test.py Pytest rig (52 tests, all green): YAML parses, every required helper / automation / template entity present, §8.T.1/§8.T.2/§8.T.3 trigger+action contract verified, tunnel URL is mode: password (sensitive), running flag defaults off, last_run initial epoch, status template covers all 6 (url, running, outbound, inbound, recovery, never_run) combos via a pure-function helper that pins the YAML strings (catches silent drift), no operator jargon in user-facing output (forbidden terms: entity ID prefixes, bash, curl, magicdns, .ts.net, tskey-), YAML idempotent (PyYAML twice → same dict), shell_command has exactly 2 probes, command_line sensors have unique unique_ids, §8.T.1 + §8.T.2 do NOT call input_text.set_value on the tunnel URL (idempotent retry), rc-entity-naming compliance on every entity_id / automation id, IKEA doc 5-step shape, no SUPERSEDED / Cron-handoff refs in user copy. - scripts/checks/tailscale-self-test-smoke.sh Bash smoke wrapper (10 standalone bash assertions + pytest rig): file presence, YAML parse, rc-naming pre- check, helpers + automations + templates pre-check, status template covers all branches, no operator jargon in status copy, secrets-leak check (no tskey- / no IPs), idempotency probe (PyYAML twice → same dict + exactly 2 probes), IKEA doc 5-step shape + translation table, §8.T.1 + §8.T.2 wiring verified, pytest rig green. - docs/setup/tailscale-self-test.md IKEA 5-step user guide: What this is / What you see (6 plain-English status phrases) / What you do (3 numbered steps) / What to do if it goes wrong (3 sub-cases) / Useful links + an operator→vanlifer translation table (Self-test / Round-trip / Outbound probe / Inbound probe / MagicDNS / ACL rules / Tunnel / Tailscale / Two-way / Persistent notification / input_button / input_text / Template sensor / Automation). ADDITIVE EDITS (3 files): - connections/remote-access/connection.yml (+45 lines) Extended wizard.setup_paths with the self_test entry (separate from the four remote-access paths A/B/C/D — doesn't pick a path, verifies the chosen path honestly works two-way). tier: b, recipe_over, estimated_time, requires_inputs, side_effects, setup_notes all documented. Path A (tier-a promotion candidate) is still wired; this slice is purely additive. - homeassistant/packages/roamcore_setup_wizard.yaml (+19 lines) New automation.rc_setup_trigger_tailscale_self_test_after_done: when rc_remote_access_setup_stage reaches 'tailscale_done', fires the 'rc_run_tailscale_self_test' event so the self-test package runs its probes. Idempotent: re-firing does NOT reset the tunnel URL or wizard progress. - scripts/check.sh (+1 line) Wire scripts/checks/tailscale-self-test-smoke.sh into the core-only chain at a stable slot next to remote-access-setup-smoke.sh (no duplicate wiring — the in-flight sub-agent's duplicate line was cleaned up). Verification - bash scripts/check.sh --core-only is GREEN on this branch tip: • Tailscale self-test smoke: 10/10 PASS • Tailscale self-test pytest rig: 52/52 PASS (0.19s) • All other 32+ connection manifest smokes: GREEN • Connection state field smoke: GREEN • PWA install smoke: GREEN (26/26) • Hub golden-image smoke: GREEN (10/10) • Final summary: 'all requested smoke checks passed' (182 PASS markers / 0 FAIL markers across the chain). - The 52 pytest tests cover: • YAML structural sanity + idempotency. • Every required helper / automation / template entity present and named per rc-entity-naming.md. • §8.T.1 / §8.T.2 / §8.T.3 trigger + condition + action contract (including idempotent retry: no input_text.set_value on the tunnel URL helper). • status template covers all 6 state combinations via the pure-function helper pinned to the YAML strings. • status output has no operator jargon (entity IDs / bash / curl / magicdns / .ts.net / tskey-). • secrets-leak grep: no tskey- / no hard-coded IPv4 in the package. • IKEA doc 5-step shape + opener plain-English + translation table present + no SUPERSEDED / Cron-handoff. • shell_command probes both have 10s timeout. • Wizard advance advances to 'map' (NOT 'done') so it doesn't skip the rest of the setup wizard. Rollback Revert this single commit. All changes are additive (no rewrites, no deletions). The new helpers / automations / sensors live in a brand-new file that nothing else in the repo depends on until the parent wizard reaches 'tailscale_done'. Removing the file + the bridge automation in roamcore_setup_wizard.yaml + the self_test entry in the connection's setup_paths block + the check.sh wire restores main to its prior state bit-for-bit. No Proxmox / HA / OpenWrt / networking / vmbr0 touched → no snapshot required (GOLDEN.md E3 N/A). GOLDEN.md alignment (re-read 2026-08-10) Product principles served (quoted verbatim from GOLDEN.md): P1 (Novice-first UX — Apple-grade onboarding. Power users get an 'Advanced mode.' Fail-softly UI everywhere.): The self-test card surfaces one plain-English sentence at a time (6 status branches, zero operator jargon); the IKEA doc walks the operator through 3 numbered steps; the recovery automation fires a plain-English notification instead of an error; the running flag defaults off so the dashboard doesn't lie about state on first boot. P2 (Mission-critical connectivity — LTE primary, Starlink failover, Tailscale-like remote access. Network failures must not lose data or lock the user out.): The two-probe round-trip catches the failure mode where a one-way tunnel still serves a cached dashboard (the user's exact symptom: 'the page loads but nothing works'); the 10s probe timeouts + 60s recovery automation ensure a stalled tunnel never locks the operator out; the tunnel URL is preserved across retries so the operator doesn't have to re-type it under stress. Engineering principles respected: E1 (Customer-facing repo): IKEA doc lives at docs/setup/tailscale-self-test.md (public MkDocs surface); developer plumbing stays in homeassistant/packages/ + tests/ + scripts/checks/. E2 (Documentation-driven): the MkDocs site picks up the new doc; cross-linked from docs/setup/guided-remote-access.md and docs/setup/local-access-fallback.md. E4 (Git fast mode): direct-to-main push on subagent/<slug>; no force-push; no PR review chain. This recovery commit completes the slice on the in-flight branch. E7 (Naming follows docs/reference/rc-entity-naming.md): every new entity_id starts with 'rc_tailscale_self_test_' or 'rc_tailscale_run_self_test'; verified by 4 dedicated pytest tests. Anti-patterns explicitly avoided (the GOLDEN.md ❌ list): ❌ Hand-configuring Victron instead of using capability discovery → N/A, no Victron changes. ❌ Touching vmbr0 without explicit Bernard override → N/A, pure Home Assistant package YAML + IKEA doc. ❌ Committing secrets or HA tokens to the repo → verified: no tskey-, no hard-coded IPs, no PII; the tunnel URL is 'mode: password' and operator-entered; the secrets-leak check is in the smoke and runs in CI. ❌ Adding 'advanced' features before the novice path is solid → the entire slice IS the novice path; no advanced mode hooks touched. ❌ Wide PRs that mix networking + UI + infra changes → only files in scope were touched; 4 NEW + 3 MODIFIED, all in the connections/remote-access + packages + docs tree. ❌ Pulling in unrelated project context → no other projects referenced; RoamCore-only. ❌ Putting internal engineering logs on the public GitHub → the IKEA doc opens with a plain-English sentence and has an operator→vanlifer translation table at the bottom. Tier discipline: kept tier: b on the connection manifest entry; Path A (tier-a promotion candidate) is the wired-up one; this slice is purely additive and does not promote any tier. Doc-target check: docs/setup/tailscale-self-test.md (IKEA 5-step, plain English, no jargon, with translation table). Confirmed in docs/ tree, not in memory/ or Cron-handoff/. Co-authored-by: Bernard <bernard@roamcore.local>
|
|
||
| import re | ||
| from pathlib import Path | ||
| from typing import Any |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 6 Tailscale wizard — sub-slice #122.d.iii
One-tap self-test that proves the Tailscale tunnel works in BOTH directions — not just that the dashboard loads (a stale one-way tunnel can still serve a cached page, which is the failure mode this slice catches).
What's in this slice
homeassistant/packages/roamcore_tailscale_self_test.yaml— the packageshell_commandprobes (10s timeout each) — outbound HTTPS via magicdns + inbound nonce POSTcommand_linesensors (HTTP code + expected/received nonce files)binary_sensors (outbound_ok / inbound_ok / ok / recovery)sensor(status — 6 plain-English branches, zero jargon)homeassistant/packages/tests/test_tailscale_self_test.py— 52 pytest tests (all green)scripts/checks/tailscale-self-test-smoke.sh— 10 bash assertions + pytest wrapperdocs/setup/tailscale-self-test.md— IKEA 5-step user guide + operator→vanlifer translation tablePlus 3 additive edits to the existing files (connection.yml manifest entry + setup_wizard bridge automation + check.sh wire).
Doctrine
GOLDEN.md alignment
Product principles served (verbatim):
Engineering principles respected: E1 (customer-facing repo), E2 (documentation-driven), E4 (git fast mode — direct-to-main on subagent branch), E7 (rc-entity-naming compliance — every entity_id starts with
rc_tailscale_self_test_/rc_tailscale_run_self_test).Anti-patterns avoided: no Victron hand-config, no vmbr0 touch, no secrets committed (verified by secrets-leak grep), no advanced-mode hooks before novice path is solid, no wide PR (only files in scope), no unrelated project context, no internal jargon in user copy.
Verification
bash scripts/check.sh --core-only→ GREEN (182 PASS markers, 0 FAIL across the chain)bash scripts/checks/tailscale-self-test-smoke.sh→ 10/10 PASSpython3 -m pytest homeassistant/packages/tests/test_tailscale_self_test.py -v→ 52/52 PASS in 0.19sRollback
Revert this single commit. All changes are additive; no rewrites, no deletions. Nothing else in the repo depends on the new helpers until the parent wizard reaches
tailscale_done.User-facing