secubox-deb/packages/secubox-rbs-sensor/nginx
CyberMind e285b48711
feat(secubox-rbs-sensor): WALL/OPAD sensor scaffold for EP06-E (closes #236) (#256)
v0.1.0 scaffold per docs/superpowers/specs/2026-05-20-secubox-wall-ep06.md
(operator scope choice: minimum viable scaffold).

Host-resident (no LXC — modem is host USB hardware per spec §8).

OPAD framework scaffolded inside this package since the spec's
prerequisites (Observer Protocol + CellObservation + verdict engine)
were absent from the repo at spec-receipt time:

* lib/rbs_sensor/observer.py — Observer Protocol + frozen-dataclass
  CellObservation / NeighbourObservation. Structural proof of the
  OPAD invariant: NO field can carry IMSI/TMSI/IMEI/MSISDN/ICCID.
  Module-level CAPTURES_SUBSCRIBER_IDENTIFIERS = False exposed via
  /api/v1/rbs-sensor/status.
* lib/rbs_sensor/verdict.py — Verdict enum (OK/SUSPECT/LIKELY_ROGUE)
  + orient() entry point. v0.1.0 returns OK; real heuristics in v0.2.
* lib/rbs_sensor/ep06.py — AT_ALLOWLIST + AT_FORBIDDEN sets +
  Ep06Modem (USB enumeration + dynamic ttyUSB* discovery) +
  Ep06Observer + Ep06Actuator stubs. SMS / phonebook / paging /
  diag / IMSI commands explicitly forbidden.

sbin/rbssensorctl follows the SecuBox CTL grammar:
  introspection: components / status / access
  lifecycle:     install / reload
  module nouns:  cell show, neighbour list
  mitigations:   mitigate {lte-only|rf-off|restore} — gated on
                 modem presence (v0.1 returns "modem-absent")

api/main.py — FastAPI on /run/secubox/rbs-sensor.sock with
/status, /components, /access, /servingcell, /neighbours,
/mitigate/{lte-only,rf-off}, /restore, /healthz.

tests/test_opad_invariant.py — 6 tests asserting:
  - CAPTURES_SUBSCRIBER_IDENTIFIERS is False
  - CellObservation has no subscriber-bound fields
  - NeighbourObservation has no subscriber-bound fields
  - AT_ALLOWLIST disjoint from AT_FORBIDDEN
  - AT_FORBIDDEN covers AT+CIMI/CMGL/CPBR
  - No AT command in the allowlist looks SMS/phonebook-related

All 6 pass locally.

udev/99-secubox-rbs-sensor.rules — symlinks the EP06 serial ports
to /dev/secubox-ep06-N (group dialout, 0660). systemd service has
SupplementaryGroups=dialout + DeviceAllow=/dev/secubox-ep06 rw.

Board-validated on gk2 (no EP06 plugged → expected "modem: absent"):

    $ rbssensorctl status
    COMPONENT    STATE        DETAIL
    modem        absent       Quectel EP06-E (USB 2c7c:0306)
    observer     idle         Ep06Observer (AT poll loop)
    actuator     idle         Ep06Actuator
    host-api     running      secubox-rbs-sensor.service (uvicorn)
    overall: yellow
    captures_subscriber_identifiers: False

    $ curl -sk -H 'Host: admin.gk2.secubox.in' \
        https://192.168.1.200:9443/api/v1/rbs-sensor/status
    {"overall": "yellow", "captures_subscriber_identifiers": false, ...}

    $ rbssensorctl mitigate lte-only
    {"ok": false, "reason": "modem-absent", "action": "lte-only"}

Lessons folded in during the board cycle:

* Python 3.11 doesn't allow backslash escapes inside f-string
  expressions. Use .format() in bash-embedded python heredocs to
  dodge both bash single-quote nesting AND the 3.11 restriction.
* debian/compat conflicts with Build-Depends debhelper-compat (= 13);
  pick one (kept the build-dep style for consistency with sibling
  modules in the repo).
* `install -d` on an existing /etc/secubox/secrets/ doesn't always
  re-apply mode/owner on bookworm — same lesson as #240 mqtt /
  #241 zigbee. (rbs-sensor doesn't need /etc/secubox/secrets/ in
  v0.1, but the fix pattern is documented in the install scripts.)

Out of scope for v0.1.0 (deferred to v0.2 once a real EP06 is
plugged + #255 mPCIe USB enumeration is solved):

* Full AT response parser for servingcell/neighbourcell (LTE+GSM+WCDMA)
* Real verdict-engine heuristics (RAT downgrade pressure, PCID
  hopping, EARFCN/band mismatch with operator priors, TAC churn
  without mobility, asymmetric power profile)
* Live mitigation execution on hardware
* AT-command mux concurrency tests

Related follow-ups filed during this work:

* #254 kernel-build: add qmi_wwan + cdc_mbim/ncm/ether (optional
  data-plane support for the EP06; #236 doesn't depend on it)
* #255 MOCHAbin DT/board: mPCIe slot USB pins not enumerating modem
  (board-level investigation needed before #236 v0.2)

Closes #236

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
2026-05-20 16:04:01 +02:00
..
rbs-sensor.conf feat(secubox-rbs-sensor): WALL/OPAD sensor scaffold for EP06-E (closes #236) (#256) 2026-05-20 16:04:01 +02:00