- tools/make_deploy_bundles.py: PMS7003·Zero2W 디스플레이 노드 번들 생성 반영(폐쇄망 동봉) - tools/harden_pi.sh: 하드닝 스크립트 갱신 - docs/superpowers: 노드 센서 통합·스모크 파일럿·대시보드 다크 설계/계획 문서 - docs/claude-config: IoT 납품·검증 스킬/룰 참조본 - review/: 프로젝트 리뷰·UI v2 목업
2.2 KiB
2.2 KiB
IoT Delivery Verification Rules
Companion to build-deployment.md (air-gapped bundles) and the
iot-airgap-deliveryskill (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
requestscall to a shared-hosting server MUST send a custom User-Agent (WAFs commonly 403 the defaultpython-requests/x.ywhile curl passes). - Debugging 403: first decide WHO rejected (JSON body = app/key; HTML = WAF/Apache),
then follow the ladder in the
iot-airgap-deliveryskill. 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.