POSA_LEAKSMS/docs/claude-config/iot-verification.rule.md
cw2007 90b93f818c chore(deploy+docs): 노드 번들 생성기·하드닝 갱신 + 설계문서
- tools/make_deploy_bundles.py: PMS7003·Zero2W 디스플레이 노드 번들 생성 반영(폐쇄망 동봉)
- tools/harden_pi.sh: 하드닝 스크립트 갱신
- docs/superpowers: 노드 센서 통합·스모크 파일럿·대시보드 다크 설계/계획 문서
- docs/claude-config: IoT 납품·검증 스킬/룰 참조본
- review/: 프로젝트 리뷰·UI v2 목업
2026-07-19 10:48:09 +09:00

2.2 KiB

IoT Delivery Verification Rules

Companion to build-deployment.md (air-gapped bundles) and the iot-airgap-delivery skill (full workflow). These are always-on behavioral rules.

Derived-key discipline (CRITICAL)

  • Master secret (API_KEY) lives only on the server config + build machine secrets dir. Leaf devices get HMAC-derived keys only (hash_hmac('sha256', '<label>', API_KEY)).
  • Servers recompute derived keys per request — never ask "where is the derived key stored on the server"; print it: php -r 'require "config.php"; echo hash_hmac(...);'
  • Never regenerate the master secret casually — it orphans every deployed node. Bundle generators must reuse the existing secret file; verify the key prefix after every run.
  • Before any commit: real secret files (config_local.py, config.local.php, secrets.h) must be gitignored AND absent from history (git log --all --full-history -- <path>). Leak → rotate.

Deploy bundle discipline

  • Source tree is truth. Never hand-edit generated deploy/ files — edit source, re-run the generator, redeploy.
  • After every source change that ships: regenerate bundles, then state which bundle goes where (server upload vs Pi copy + systemctl restart <service>).

HTTP client discipline (shared-hosting targets)

  • Every Python requests call to a shared-hosting server MUST send a custom User-Agent (WAFs commonly 403 the default python-requests/x.y while curl passes).
  • Debugging 403: first decide WHO rejected (JSON body = app/key; HTML = WAF/Apache), then follow the ladder in the iot-airgap-delivery skill. Don't guess — curl it.

Render verification (device displays)

  • Never ship display-render changes verified only by reading code. Render synthetic worst-case frames to PNG at exact panel resolution, inspect them visually, show the user previews (SendUserFile), THEN deploy.

Poll-heavy endpoint rules

  • Time-window SQL must ride an index (composite indexes need their leading column in WHERE — loop per-entity if needed). Cap result sets with LIMIT. Whole handler in try/catch with generic error JSON. File-based per-IP rate limit that fails OPEN (monitoring must not die from its own throttle). JSON responses evolve additively only.