Chapter 9 — Programming II
Lesson map
Lesson 09 published. Map, example, EX025.
flowchart TD
N0["Learning outcomes"]
N1["9.1 Schema without payloads"]
N2["9.2 Idempotent upserts"]
N3["9.3 Property tests for zones"]
N4["Practice note"]
N5["9.1b Schema evolution without downtime"]
N6["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6
N6 --> EX["Worked example"]
EX --> Q["Exercise EX025"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["9.1 Schema without payloads"]
N2["9.2 Idempotent upserts"]
N3["9.3 Property tests for zones"]
N4["Practice note"]
N5["9.1b Schema evolution without downtime"]
N6["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> Q["EX025"]
[Learning outcomes]
|
v
[9.1 Schema without payloads]
|
v
[9.2 Idempotent upserts]
|
v
[9.3 Property tests for zones]
|
v
[Practice note]
|
v
[9.1b Schema evolution without downtime]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX025]
Learning outcomes
You will (1) design a schema for OT findings that forbids exploit recipes; (2) implement idempotent updates keyed by asset and weakness; (3) property-test zone rules.
9.1 Schema without payloads
Store title, asset, zone, weakness class, evidence hash, consequence bound, protective layers intact, status. Reject fields named payload, shell or exploit. Evidence lives in a sealed store; the ticket holds the hash.
Lena's schema rejects a record outright if a forbidden field appears, rather than stripping it quietly, so the person who submitted it learns not to. Consequence bounds and intact protective layers are separate fields, which lets the safety engineer filter findings that touch SIS-B. The evidence hash links each ticket to its sealed proof without copying any of it into the ticket system.
9.2 Idempotent upserts
Two scanners reporting the same open Modbus write on PLC-A must become one finding. Fingerprint = (asset, weakness class, register-or-path). Retries and re-imports leave one row.
Lena tests this by importing the same scanner output twice and by importing two scanners' reports of the same issue; both cases must leave exactly one finding. The fingerprint uses the register or path, not the scanner's own wording, because two tools describe the same weakness differently. When fingerprints collide for genuinely different problems, a person splits them and records why.
9.3 Property tests for zones
State: "for every host in the office zone and every SIS register, permit is false". Generate synthetic hosts and assert. Property tests catch the bug where a new office subnet was added to inventory but not to the deny side of the allow-list.
Synthetic case — Ashford Batch Plant. After the FW-12 finding, Lena added a property test: no L4 host may have a permit path to L1-SIS. CI runs it on every firewall-export change.
The test runs on synthetic hosts drawn from the inventory.
9.4 Errors and limits
Schemas drift; version them. Property generators that never emit the new subnet miss the bug they were written to catch — include inventory diffs as inputs.
Lena feeds the property test with the latest inventory diff, so every new subnet is tested in the next run. The schema has a version field, and older records are migrated with a recorded script rather than edited by hand. When a test is changed, she checks that it still fails on the original bug, since a property that can no longer fail protects nothing.
Practice note
When someone asks for a "just this once" exception host, require a time-boxed exception object in the schema with an expiry and an owner. Exceptions without expiry become permanent conduits.
9.1b Schema evolution without downtime
When the CNHP finding schema gains a required field, such as the work-permit number, deploy a two-phase change: first accept and persist the field as optional while backfilling; then flip the validator to required. Windows mid-flight must not break because a mobile client is one version behind. Publish the schema version in API responses so the field tablets and the monitor's exporter can refuse to write when incompatible. Bulk imports from scanners must pass the same validation path as interactive creates, including forbidden-field checks, or payloads will sneak in through the trusted import side door.
Exercises
- EX025 — Reject. Write a validation rule that rejects payload-like fields. Rubric: 3 = rule + failing example; 2 = rule; 1 = idea; 0 = none.
- EX026 — Fingerprint. Why do two reports of PLC-A register 40050 collapse? Rubric: 3 = same fingerprint; 2 = "same finding"; 1 = vague; 0 = wrong.
- EX027 — Property. State one property after adding a DMZ zone. Rubric: 3 = e.g. L4 reaches L2 only via L3.5; 2 = informal; 1 = wrong; 0 = none.
Synthesis
Schemas, idempotency and properties keep OT security tooling boring — in the good sense.
Continue studying — chapter 09 of 50
← Chapter 08 (draft) · Course chapter index · Chapter 10 (draft) →