Wave 9 #123.c.ii: Phase 7 Security Review — tier-a manifest + services + data-layer + pytest + smoke + IKEA runbook - #117
Open
bernardc6 wants to merge 2 commits into
Open
Conversation
added 2 commits
August 6, 2026 19:06
…ery) Context: Phase 7 #123.c (Security Review) was dispatched at 2026-08-06 18:09 UTC to subagent/phase7-security-review. The sub-agent wrote the core service module but got interrupted before commit/push. Per the cross-project-triage recovery protocol, the orchestrator takes ownership of the in-flight file + commits + pushes + opens the PR on the agent's behalf. This is sub-slice #123.c.i — the core service module. The full #123.c spec still requires: tier-a connection manifest (connections/security-review/), services.yaml wiring (3 services), data-layer package (roamcore_security_review.yaml with 4 input helpers + 4 template sensors + 4 §8 MANDATORY automations), pytest rig (~20 tests), bash smoke (~10 assertions), and IKEA runbook. These land as #123.c.ii follow-up sub-slices. Changes: + homeassistant/custom_components/roamcore/security.py (NEW, 883 LOC) - RCApiTokenManager: rotates RC_API_TOKEN with backup-before-mutate discipline (writes backup to /config/.storage/.roamcore_security_backup.jsonl BEFORE updating /config/.storage/roamcore_security.json); atomic .storage/ write via .tmp + os.replace; idempotent (re-running appends, not overwrites, unless force=True); 256-bit entropy via secrets.token_urlsafe(32); reads existing token age for the 'days-old' status message. - SSHAuditReader: read-only audit of /etc/ssh/sshd_config; parses 5 canonical hardening settings (PasswordAuthentication, PermitRootLogin, PubkeyAuthentication, Port, PermitEmptyPasswords); find_risky_settings() returns plain-English warnings ('Your SSH allows password login — switch to keys for safety') per Bernard 2026-08-04 doctrine; never mutates sshd_config. - FirewallAuditReader: read-only audit of nft + iptables-save; parses rules from both nftables.conf and iptables-save output; find_risky_rules() flags ACCEPT rules with no saddr filter on sensitive ports (SSH 22, HA 8123, MQTT 1883, RDP 3389, etc.); plain-English warnings ('Port 22 (SSH) is open to the whole internet — restrict to your IP range'). - register_security_services(hass): wires 3 RoamCore services — roamcore.rotate_api_token, roamcore.audit_ssh, roamcore.audit_firewall — into HA's service registry; lazy-imports homeassistant.core so the module is testable without HA runtime. - plain_english_status(): maps status codes to vanlifer-facing strings ('Your van is locked down — access codes fresh, SSH key-only, firewall tight.'). - No HA imports in core class bodies (stdlib only) so pytest fixtures can import + bench the module without spinning up HA. - No hardcoded URLs, no hardcoded passwords, no /home/<user> paths (secrets-leak guard ready for the pytest rig). - Constants exported: SECURITY_TILE_PREFIX='rc_security_review_' (compliant with docs/reference/rc-entity-naming.md; Hub-level package will use this prefix for tile entities in #123.c.ii). Verification: - python3 -c 'import ast; ast.parse(...)' → OK (module parses). - Module size: 33665 bytes, 883 lines. - Module is import-safe (no top-level HA imports — only inside register_security_services, which is only called from HA's service setup hook). - bash scripts/check.sh --core-only → GREEN exit 0 on the branch tip; no existing tests broken. - Public surface (classes + functions) verified via AST scan: RCApiTokenManager, SSHAuditReader, FirewallAuditReader, TokenRecord, SSHConfig, FirewallRule, plain_english_status, register_security_services, _service_name_for_port — all present. GOLDEN.md alignment (re-read 2026-08-06 19:03 UTC): - P2 (Mission-critical connectivity) served — security review is the canonical prevention for the 'lockout' worst-case the principle names. SSH-keys-only + firewall-tight + fresh access codes = no lockout. - P6 (OpenClaw first-class) served — 3 services (rotate_api_token, audit_ssh, audit_firewall) are exposed for OpenClaw to call through the existing roamcore-agent-actions-allowlist surface. - E3 (Backup + rollback discipline) respected — rotate_token() writes the backup file BEFORE updating .storage/, atomic write via .tmp + os.replace, idempotent (re-running appends). - E7 (rc-entity-naming.md) respected — SECURITY_TILE_PREFIX constant = 'rc_security_review_' (compliant with the doc's 'prefix with rc_<subsystem>_' rule). - Anti-patterns avoided: ❌ no Victron hand-config (purely generic SSH + firewall) ❌ no vmbr0 touch (no networking config mutation at all) ❌ no committed secrets (token gen via /dev/urandom) ❌ no wide PR (pure security-review scope) ❌ no unrelated project context ❌ no internal engineering logs in user-facing copy User-facing: Tells me in plain English whether my van is locked down — SSH keys only, firewall tight, access codes fresh — so I can fix small problems before they become lockouts, without having to read technical jargon. Rollback: git revert <SHA>; no state to recover (no Proxmox/HA/ OpenWrt/networking change; pure repo-local code).
…s + data-layer + pytest + smoke + IKEA runbook Context: Phase 7 #123.c Security Review slice — sub-slice #123.c.ii ships the tier-a connection manifest + the 3 service definitions + the data-layer package + the 22 pytest tests + the 10 bash smoke assertions + the IKEA user-facing runbook on top of the foundation service module that landed at #123.c.i (commit 63145f8 on branch subagent/phase7-security-review). The foundation service module (homeassistant/custom_components/roamcore/security.py, 883 LOC, stdlib-only Python) is the canonical umbrella for the security- review surface; this slice adds the connection-level artefacts that turn the foundation into a tier-a connection. Changes: - connections/security-review/connection.yml (NEW): tier-a connection manifest for the security-review surface (12 contract tiles + 4 §8 MANDATORY automations + 3 RoamCore services + vendor-neutral tiles + 1-tap install). - connections/security-review/__init__.py (NEW): DOMAIN marker + SECURITY_TILE_NAMES tuple + SECURITY_TILE_PREFIX + security review status constants for the audit + the helper package + the pytest rig. - connections/security-review/README.md (NEW): vendor-neutral 1-paragraph description of the security-review surface. - connections/security-review/docs/recipe.md (NEW): 5-step IKEA developer recipe (internal only, NOT user-facing). - connections/security-review/tests/test_connection_yml.py (NEW): 11 manifest-honesty tests (manifest honoured + tier-a markers + recipe present + rc-entity-naming compliance + idempotency + secrets-leak guard). - homeassistant/custom_components/roamcore/services.yaml (MODIFY): 3 new service definitions for roamcore.rotate_api_token + roamcore.audit_ssh + roamcore.audit_firewall (vendor-neutral + plain-English). - homeassistant/custom_components/roamcore/__init__.py (MODIFY): wired register_security_services(hass) into async_setup_entry (mirrors the existing Hub Backup pattern; wrapped in try/except so the failure never breaks HA startup). - homeassistant/packages/roamcore_security_review.yaml (NEW): data-layer package with 4 input helpers + 4 template sensors + binary_sensor healthy + 3 buttons + 4 §8 MANDATORY automations (rotate-token + audit-ssh + audit-firewall + warn-rotation-age). - homeassistant/packages/tests/test_security_review.py (NEW): 22 pytest tests covering the YAML package + the 3 service registrations + the 4 helper entities + the 4 template sensors + the 4 §8 automations + rc-entity-naming compliance + idempotency + secrets-leak guard. - scripts/checks/security-review-smoke.sh (NEW): 10 bash assertions wiring connection manifest + YAML package + 3 service definitions + rc-entity-naming + idempotency + secrets-leak. - scripts/check.sh (MODIFY): wired the new smoke into the chain. - homeassistant/packages/tests/test_connection_state_field.py (MODIFY): bumped expected manifest count from 33 to 34 (the security-review connection is the 34th manifest). - docs/runbooks/security-review.md (NEW): IKEA 5-step vanlifer-facing runbook (5 numbered steps + 3-line troubleshooting + useful links; NO bash commands in §1-§4; NO operator-speak jargon). Verification: - bash scripts/check.sh --core-only → exit 0 (GREEN) - bash scripts/checks/security-review-smoke.sh → PASS: 10 / FAIL: 0 - python3 -m pytest homeassistant/packages/tests/test_security_review.py → 22/22 PASS - python3 -m pytest connections/security-review/tests/test_connection_yml.py → 11/11 PASS - python3 -m pytest homeassistant/packages/tests/test_connection_state_field.py → 22/22 PASS (manifest count bumped 33 → 34) - secrets-leak guard: grep -rIn -E 'password=|token=|/home/[a-z]' over the new files returns only the guard-pattern strings themselves (intended markers, not actual leaks). GOLDEN.md alignment: - P1 (Novice-first UX) — the IKEA runbook opens with one plain-English sentence a vanlifer understands ('Tells you in plain English whether your van is locked down — SSH keys only, firewall tight, access codes fresh — so you can fix small problems before they become lockouts, without having to read technical jargon.'); the dashboard tile is one-tap (the rotate-token + audit-ssh + audit-firewall buttons trigger the 3 RoamCore services synchronously). - P2 (Mission-critical connectivity) — security review IS the canonical prevention for the 'lockout' worst-case (per the directive §'Phase 7 delivery' / Gate F). - P6 (OpenClaw first-class) — 3 services exposed for OpenClaw to call through the existing agent-actions-allowlist connection (roamcore.rotate_api_token + roamcore.audit_ssh + roamcore.audit_firewall). - E1 (Customer-facing repo) — no internal logs in the user tree; the runbook in docs/runbooks/ is the public surface (5-step IKEA + 3-line troubleshooting + useful links); developer plumbing stays in connections/security-review/docs/ recipe.md. - E2 (Documentation-driven) — runbook = source of truth for the user; package YAML = source of truth for the data layer; pytest rig = source of truth for the contract assertions; smoke check = source of truth for the chain. - E3 (Backup + rollback discipline) — rotate_token() writes backup BEFORE updating .storage/ (backup-before-mutate); atomic write via .tmp + os.replace; idempotent append-not- overwrite; the SSH + firewall audit is READ-ONLY by design (no mutation of /etc/ssh/sshd_config or /etc/nftables.conf); no Proxmox / HA / OpenWrt / networking change in this slice. - E7 (rc-entity-naming.md) — every new entity starts with rc_security_review_ (the SECURITY_TILE_PREFIX constant from security.py). User-facing one-liner: > Tells me in plain English whether my van is locked down — SSH > keys only, firewall tight, access codes fresh — so I can fix > small problems before they become lockouts, without having to > read technical jargon. Anti-patterns avoided: - ❌ no Victron hand-config (purely generic SSH + firewall) - ❌ no vmbr0 touch (no networking config mutation at all) - ❌ no committed secrets (the secrets-leak guard grep enforces this) - ❌ no wide PR (pure security-review scope, 13 files only) - ❌ no unrelated project context - ❌ no internal engineering logs in user-facing copy Rollback: - git revert <commit-sha> + git push origin main (no Proxmox / HA / OpenWrt / networking change to roll back) - the foundation service module (security.py) at #123.c.i is untouched by this slice; rolling back the slice leaves the foundation in place - the connection ID (security_review) is reserved by the DOMAIN constant in __init__.py; rolling back the slice removes the connection but the ID is reusable for a future re-implementation
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.
Context
Phase 7 #123.c Security Review slice — sub-slice #123.c.ii ships the tier-a connection manifest + the 3 service definitions + the data-layer package + the 22 pytest tests + the 10 bash smoke assertions + the IKEA user-facing runbook on top of the foundation service module that landed at #123.c.i (commit 63145f8 on branch subagent/phase7-security-review). The foundation service module (homeassistant/custom_components/roamcore/security.py, 883 LOC, stdlib-only Python) is the canonical umbrella for the security-review surface; this slice adds the connection-level artefacts that turn the foundation into a tier-a connection.
Changes
Verification
GOLDEN.md alignment
User-facing one-liner
Anti-patterns avoided
Rollback