Skip to content

Wave 9 #123.c.i: Phase 7 Security Review — core service module (recovery) - #116

Open
bernardc6 wants to merge 1 commit into
mainfrom
subagent/phase7-security-review
Open

Wave 9 #123.c.i: Phase 7 Security Review — core service module (recovery)#116
bernardc6 wants to merge 1 commit into
mainfrom
subagent/phase7-security-review

Conversation

@bernardc6

Copy link
Copy Markdown
Collaborator

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; atomic .storage/ write via .tmp + os.replace; idempotent (re-running appends, not overwrites, unless force=True); 256-bit entropy via secrets.token_urlsafe(32).
  • SSHAuditReader: read-only audit of /etc/ssh/sshd_config; parses 5 canonical hardening settings; find_risky_settings() returns plain-English warnings per Bernard 2026-08-04 doctrine ("Your SSH allows password login — switch to keys for safety"); never mutates sshd_config.
  • FirewallAuditReader: read-only audit of nft + iptables-save; find_risky_rules() flags ACCEPT rules with no saddr filter on sensitive ports; 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).

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) respectedrotate_token() writes the backup file BEFORE updating .storage/, atomic write via .tmp + os.replace, idempotent (re-running appends).
  • E7 (rc-entity-naming.md) respectedSECURITY_TILE_PREFIX constant = 'rc_security_review_' (compliant with the doc's "prefix with rc__" 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 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.

Rollback

git revert <SHA>; no state to recover (no Proxmox/HA/OpenWrt/networking change; pure repo-local code).

Follow-up sub-slice (#123.c.ii)

The full Phase 7 Security Review spec still requires:

  • Tier-a connection manifest at connections/security-review/ (manifest + recipe + tests + IKEA doc)
  • homeassistant/custom_components/roamcore/services.yaml wiring of the 3 services
  • Data-layer package homeassistant/packages/roamcore_security_review.yaml with 4 input helpers + 4 template sensors + 4 §8 MANDATORY automations
  • Pytest rig (~20 tests) at homeassistant/packages/tests/test_security_review.py
  • Bash smoke (~10 assertions) at scripts/checks/security-review-smoke.sh
  • IKEA runbook at docs/runbooks/security-review.md

Sub-sliced from XL #123.c to keep each PR ≤ ~500 LOC and checkable.

Closes: Wave 9 #123.c (partial — sub-slice #123.c.i)
Refs: directive §"Phase 7 delivery" + Gate F

…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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant