Skip to content

Commit bad86ee

Browse files
eastmadcclaude
andcommitted
feat(ics-protocol): Rule digitalandrew#39 walker triplet + Pydantic Literal + Rule #45/46 gates (Phase 1.C)
Rule #52 instance digitalandrew#3 / Phase 1.C: inner/outer/safe walker triplet per Rule digitalandrew#39, consuming the Session 1 ICS protocol catalog scaffold (``catalog.py`` / ``resolver.py`` / ``snapshot.py``) via Rule digitalandrew#16 ``get_detection_roots(firmware)`` × binary head-byte slice × ``resolve_all()`` × Rule #35c JSONB stamp from Phase 1.B. Walker (NEW: ``backend/app/services/ics_protocol_walker.py``): - ``_do_ics_protocol_walk(db, firmware_id)`` — INNER pure-logic; pins catalog snapshot at entry (W2-β §SC5-NEW-ICS-S2-β); clears stale ics_protocol_walk_result on entry (W2-β §SC5-NEW-ICS-S2-δ); iterates detection roots × binary candidates × resolve_all; reads exit snapshot + flags drift as consistency_warning. - ``run_ics_protocol_walk_background(firmware_id)`` — OUTER Rule digitalandrew#33 .a state machine; cycles queued → running → completed | failed; failure persistence on FRESH session per Rule digitalandrew#33 .b; clears partial JSONB on failure (W2-β §SC5-NEW-ICS-S2-δ). - ``auto_ics_protocol_walk_firmware_safe(firmware_id)`` — SAFE Rule digitalandrew#39 .safe contract; runs INNER + stamps result + does NOT mutate status (leaves idle so operator MCP trigger doesn't 409); structured log on exception per Rule #51 partner. Pydantic ``IcsProtocolWalkStatus = Literal[idle/queued/running/completed/ failed]`` added to ``app/schemas/firmware.py`` — Rule digitalandrew#33 .c typo-gate at trigger MCP / status reader boundary; DB CHECK ck_firmware_ics_protocol_walk_status (Phase 1.A) is the durable safety floor. Bounded scan budget: 32 KiB head per binary, 2000 binaries per walk, 64 B–50 MB size band, ``_BINARY_EXT_ALLOWLIST`` for fast filesystem rejection. Per Rule digitalandrew#5 all blocking filesystem reads wrapped in ``loop.run_in_executor``. Test battery (Rule digitalandrew#36 + Rule #45 + Rule #46 paired META-CANARIES; Rule #35b live canaries against tests._live_db.make_live_db): - test_walker_no_execute_no_decrypt: tokenize-walk over walker source; asserts NO subprocess/decrypt/eval/exec patterns; whitespace-tolerant per Rule #45 EFS-DDF lesson - test_walker_no_execute_gate_actually_fires: Rule #46 paired META-CANARY; synthesizes subprocess.run + asyncio.create_subprocess_exec + .decrypt( in-memory; asserts gate matches all 3 - test_walker_empty_firmware_returns_empty_aggregate: live canary; empty firmware → empty aggregate + no_detection_roots error - test_walker_clears_stale_jsonb_on_entry: live canary; W2-β §SC5-NEW-ICS-S2-δ — stale ghost_protocol JSONB cleared after INNER - test_walker_detects_mid_walk_snapshot_drift: W2-β §SC5-NEW-ICS-S2-β paired META-CANARY; mocked drifting catalog → consistency_warning populated; pair-canary test_walker_no_drift_when_snapshot_stable confirms gate doesn't false-fire - test_walker_triplet_exports_all_three_runners: Rule digitalandrew#11 import smoke - test_walker_uses_jsonb_stamp_helper_not_direct_dict_assign: Rule #35c partner — direct JSONB assignment bypasses provenance contract - test_ics_protocol_walk_status_literal_matches_db_check_values: Rule digitalandrew#33 .c — Literal ↔ DB CHECK pairwise agreement All 20 ICS Phase 1.B+1.C tests green: docker compose exec -T backend uv run pytest tests/test_ics_protocol_walker.py tests/test_jsonb_normalizers.py -k "ics_protocol" -q → 20 passed in 2.30s Phase 1.D (next): walker_registry + DUAL reaper registration (STATE_MACHINE_REAPER_CONFIGS 8→9 AND WALKER_REAPER_CONFIGS 25→26) + Rule #46 size-lock META-CANARY updates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7c6405f commit bad86ee

3 files changed

Lines changed: 921 additions & 0 deletions

File tree

backend/app/schemas/firmware.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,17 @@
216216
"Other",
217217
]
218218

219+
# ICS protocol catalog walker (CLAUDE.md Rule #52 instance #3 — Session 2,
220+
# 2026-05-22). Rule #33 .c Pydantic Literal typo-gate at the trigger MCP
221+
# tool / status reader boundary. The DB CHECK constraint
222+
# ``ck_firmware_ics_protocol_walk_status`` (alembic revision 1c52a4b5c6d7)
223+
# is the durable safety floor; this Literal adds compile-time typo
224+
# detection for new callers. Mirrors the ContainerWalkStatus /
225+
# SystemdWalkStatus / EfsWalkStatus / EtlWalkStatus shapes.
226+
IcsProtocolWalkStatus = Literal[
227+
"idle", "queued", "running", "completed", "failed"
228+
]
229+
219230

220231
class FirmwareUploadResponse(BaseModel):
221232
model_config = {"from_attributes": True}

0 commit comments

Comments
 (0)