Second demo fixture (public-sample shape) to complement the all-rules
pump_station.st: a timed pedestrian-crossing state machine adapted from
the OpenPLC traffic-light example, extended with a SCADA/Modbus uplink and
a maintenance override. Mostly sound control logic with three planted,
field-realistic defects (hardcoded SCADA password, cleartext Modbus master,
maintenance mode that drops the pedestrian safety permit).
The regression test asserts the scanner surfaces those defects while staying
quiet on the guarded duty-cycle division and the JMP-free CASE machine —
demonstrating low false positives on real-world-shaped code.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI clippy (rust 1.94.0, overly_complex_bool_expr) flagged the disabling
check as a logic bug: the `watchdog && matches!(value, Int(0))` term is
fully subsumed by the preceding `matches!(value, Int(0))`. Simplify to
`Bool(false) || Int(0)` — behavior is unchanged (a safety/watchdog signal
driven to FALSE or 0 is still a bypass), and `watchdog` stays used in the
outer guard. All 5 PLC tests still pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements ScanType::PlcControlLogic — the missing piece for PlcSps targets,
which previously classified but ran no scan.
New `pipeline::plc`:
- A real IEC 61131-3 Structured Text front end: lexer + recursive-descent parser
→ AST (POUs, typed VAR sections, statements, expressions). Tolerant recovery so
odd constructs never sink a file.
- PLCopen XML extractor: pulls each ST POU's interface vars + `<ST>` body and
reconstructs equivalent ST, so raw `.st` files and PLCopen projects share one
analysis path.
- Eight semantic, guard-aware rules over the AST → findings: hardcoded
credentials, default/weak passwords, safety-interlock/watchdog bypass, array
indexed by unvalidated input, division without a zero-guard (suppressed when an
enclosing `IF <d> <> 0` proves it), insecure comm (auth/encryption disabled),
and cleartext OT protocol ports, plus unstructured JMP. Each carries CWE +
remediation.
- `PlcControlLogicScanner` (Scanner impl) walks the project tree and emits
`Finding`s (dedup fingerprint, file, line, severity).
Wired into `run_target_pipeline`: when the scan plan includes PlcControlLogic,
`run_plc_scan` ingests the PlcProject artifact, analyzes it, and persists the
findings (findings_count handled by run_target).
Demo fixtures under examples/plc-demo/ (a vulnerable pump-station `.st` + a
PLCopen `conveyor.xml`). Tests: parser, all-rules-fire, guarded-clean-is-quiet,
and an end-to-end tree scan — 5 passing.
Adds `roxmltree` (read-only XML) for PLCopen parsing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each deploy job now builds the per-service image, pushes to the
private registry as :latest and :sha, then triggers an HMAC-signed
orca redeploy webhook. Coolify webhooks are no longer used.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>