diff --git a/.gitignore b/.gitignore index 4191f35..a943b28 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ build/ +build-fuzz/ +build-tsan/ *.o *.obj *.a diff --git a/COMPLIANCE.md b/COMPLIANCE.md index 3ac664d..45ad031 100644 --- a/COMPLIANCE.md +++ b/COMPLIANCE.md @@ -1,12 +1,13 @@ # SECS/GEM Compliance A per-capability accounting against the foundational SEMI standards -**E5 (SECS-II)**, **E30 (GEM)**, **E37 (HSMS)**, **E4 (SECS-I)**, plus -the full GEM 300 stack: **E40** (process jobs), **E94** (control jobs), -**E87** (carriers), **E90** (substrates), **E116** (equipment -performance tracking), **E120** (common equipment model), **E157** -(module process tracking), **E84** (parallel I/O), **E148** (time -synchronization), **E39** (object services), plus **E5 §13** wafer maps. +**E5 (SECS-II)**, **E30 (GEM)**, **E37 (HSMS, SS + GS)**, **E4 (SECS-I)**, +plus the full GEM 300 stack: **E40** (process jobs), **E42** (formatted +process programs), **E94** (control jobs), **E87** (carriers), **E90** +(substrates), **E116** (equipment performance tracking), **E120** (common +equipment model), **E157** (module process tracking), **E84** (parallel +I/O), **E148** (time synchronization), **E39** (object services), plus +**E5 §13** wafer maps. > **Status.** Every GEM Fundamental and every GEM Additional capability > that E30 binds to a concrete SECS-II message set is implemented, and @@ -227,7 +228,7 @@ Legend: ## 5. Message coverage matrix -149 SECS-II messages in the catalog, spanning streams 1, 2, 3, 5, 6, 7, 9, 10, 12, 14, 16. +164 SECS-II messages in the catalog, spanning streams 1, 2, 3, 5, 6, 7, 9, 10, 12, 14, 16. | Pair | Direction | Status | Notes | |------------------|-----------|--------|-------| @@ -345,7 +346,7 @@ walks ~20 SECS transactions end-to-end: 23. `S1F15`/`S1F16` Request Offline. 24. `Separate.req` → clean close on both sides. -Unit tests: **291 cases / 1515 assertions pass** (`docker compose run --rm tests`). +Unit tests: **445 cases / 2753 assertions pass** (`docker compose run --rm tests`). The suite includes integration tests that drive a real `hsms::Connection` over a loopback socket pair to verify the E37 §7.2 / §7.4 / §7.7 edge cases — not just the happy path. @@ -398,9 +399,8 @@ compliance claim. | Item | Why it's out of scope | |---------------------------------------|----------------------| -| Multi-block SECS-I transfers | Multi-block is a **SECS-I** concept for 244-byte serial frames. HSMS allows arbitrarily large bodies (up to the codebase's 16 MiB cap), so multi-block is structurally not needed. E37-based GEM equipment does not require it. | -| HSMS-GS (multi-session) | Out of scope — modern HSMS-SS covers virtually all current GEM equipment. | | Equipment Processing States (concrete states) | E30 §6.3 says the specific states are tool-defined. We provide the engine (`ControlTransitionTable` + the YAML loader); equipment vendors load their concrete states (IDLE / SETUP / READY / EXECUTING / PAUSE / …) the same way `data/control_state.yaml` is loaded today. Spec-compliant either way. | +| Serial-port wiring for SECS-I | The SECS-I FSM (`secsi::Protocol`) is fully implemented and tested end-to-end over the asio TCP transport (`secsi::TcpTransport`). The serial-port driver (asio `serial_port` wrapper around the same FSM) is a few hundred lines of straightforward wiring that hasn't been written yet — most modern GEM equipment runs HSMS. Plug it in by mirroring `TcpTransport`. | --- diff --git a/FAQ.md b/FAQ.md index 2ee4e25..14eb4f8 100644 --- a/FAQ.md +++ b/FAQ.md @@ -210,7 +210,7 @@ Both are necessary; neither replaces the other. See VERIFICATION.md. ## How do I bring this to a customer site? Run through the five external proofs in -[README's proof table](README.md#proof-of-feature-completeness) at +[the eight commands in PROOFS.md](PROOFS.md) at the customer's network. Then walk MES_INTEROP.md against their actual MES. Then deploy per [SECURITY.md](SECURITY.md) for the nftables / stunnel / signing setup. Then page on the metrics from @@ -219,7 +219,9 @@ INTEGRATION.md §6.4. ## What's not implemented? See [COMPLIANCE.md](COMPLIANCE.md) §8 ("Explicitly out of scope") -for the honest list. The short version: multi-block SECS-I -transfers (irrelevant on HSMS), tool-specific Equipment Processing -States (the engine is there, vendors plug in their states), and -GEM RTS certification (paid third-party gate, not a code feature). +for the honest list. The short version: tool-specific Equipment +Processing States (the engine is there, vendors plug in their +states), the serial-port driver for SECS-I (the FSM is wired +end-to-end over TCP, the asio `serial_port` glue is a deferred +follow-up), and GEM RTS certification (paid third-party gate, not +a code feature). diff --git a/GLOSSARY.md b/GLOSSARY.md index d4cacd4..53aeed9 100644 --- a/GLOSSARY.md +++ b/GLOSSARY.md @@ -149,7 +149,7 @@ TA3 (BUSY duration) live alongside the signals — see | **The router** | `gem::Router` — `(stream, function) → handler` dispatch table. | | **The codec** | `secs2::encode` / `secs2::decode` for the wire bytes. | | **The catalog** | `data/messages.yaml` — every SECS-II message we ship, codegen'd to `messages.hpp`. | -| **The proof** | The 8 commands in [README.md](README.md#proof-of-feature-completeness). | +| **The proof** | The 8 commands in [PROOFS.md](PROOFS.md). | | **The bench** | `apps/secs_bench.cpp` — single-threaded throughput / latency / memory harness. | | **The fuzz** | `tests/test_robustness_fuzz.cpp` — randomized property test of the model. | diff --git a/PROOFS.md b/PROOFS.md new file mode 100644 index 0000000..22eb894 --- /dev/null +++ b/PROOFS.md @@ -0,0 +1,72 @@ +# Proof of feature-completeness + +"Feature-complete" is a claim that the code must prove, not the +README. These eight commands are the proof. If they all exit zero +on a fresh clone, the codebase implements what +[COMPLIANCE.md](COMPLIANCE.md) claims. + +| # | Command | What it proves | +|---|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| 1 | `docker compose run --rm tests` | **445 test cases / 2 753 assertions** pass: every store, FSM, codec, parser, persistence path | +| 2 | `docker compose run --rm builder /app/build/secs_conformance --host server --port 5000` | **47 wire-level conformance checks** PASS against a live passive equipment | +| 3 | `docker compose run --rm interop python3 /app/interop/host_vs_cpp_server.py --host server` | **31 interop checks** PASS against secsgem-py 0.3.0 (the Python reference impl) | +| 4 | `SECSGEM_ROBUSTNESS_SOAK=1 docker compose run --rm builder /app/build/secsgem_tests -tc='*soak*'` | **100 000 random tool operations** execute with all invariants and persistence round-trips holding | +| 5 | `docker compose run --rm builder /app/build/secs_server --validate-config --config /app/data/equipment.yaml --state-table /app/data/control_state.yaml --pj-state-table /app/data/process_job_state.yaml --cj-state-table /app/data/control_job_state.yaml` | Every shipped YAML config passes structural + referential validation | +| 6 | `docker compose run --rm builder bash /app/interop/tshark_validate.sh` | **69 HSMS frames** dissected by Wireshark's HSMS dissector (independent third codec) with no malformed packets | +| 7 | `bash interop/secs4j_validate.sh` | **55 cross-validation checks** PASS against [secs4java8](https://github.com/kenta-shimizu/secs4java8) (independent Java implementation), covering S1/S2/S3/S5/S6/S7/S10/S14/S16, the full E40 PJ body, dynamic event reports + unsolicited S6F11 / S5F1 observation, alarm management, spool, PP management, terminal services, limits, trace, E39, and the GEM 300 streams secsgem-py couldn't easily drive | +| 8 | `cmake -B build-fuzz -DSECSGEM_FUZZ=ON && build-fuzz/fuzz_secs2_decode -max_total_time=60` | **200 000+ random inputs** through `secs2::decode`, **1.4 M+** through `try_parse_sml` per 60 s lane, ASan + UBSan + libFuzzer coverage, **0 crashes** | + +Plus, on every push to `main`, [Gitea Actions](.gitea/workflows/ci.yml) +runs both a **Release build + full test suite** and a separate +**ThreadSanitizer lane** that builds with `-fsanitize=thread` and +fails on any race. All 445 cases / 2 753 assertions pass under TSan +clean. + +## Per-standard test coverage + +Every claimed standard has dedicated tests. Counts are +`grep -c TEST_CASE`; cross-cutting tests (e.g. `test_robustness_fuzz`, +`test_gem300_scenario`) exercise multiple standards in concert. + +| Standard | Test files | Cases | +|-----------------------------------|-------------------------------------------------------------------------------------------|------:| +| **E5** — SECS-II encoding | `test_secs2`, `test_sml`, `test_messages`, `test_e5_kat`, `test_identifier_wildcards`, `test_fuzz` | 139 | +| **E5 §13** — exceptions | `test_exceptions`, `test_exception_persistence` | 16 | +| **E4** — SECS-I transport | `test_secsi`, `test_secsi_timers`, `test_secsi_tcp` | 27 | +| **E37** — HSMS (SS + GS) | `test_hsms`, `test_hsms_connection`, `test_hsms_timers`, `test_hsms_s9`, `test_hsms_gs`, `test_hsms_gs_integration`, `test_s9_fallback`, `test_concurrency` | 34 | +| **E30** — GEM core | `test_control_state`, `test_communication_state`, `test_host_handler`, `test_data_model`, `test_loader`, `test_config_validate` | 71 | +| **E40** — process jobs | `test_process_jobs` | 21 | +| **E94** — control jobs | `test_control_jobs` | 9 | +| **E42** — formatted PP | `test_e42_formatted_pp` | 6 | +| **E87** — carriers + load ports | `test_carriers`, `test_carrier_state`, `test_carrier_persistence`, `test_e87_wire_scenarios` | 27 | +| **E90** — substrate tracking | `test_substrates`, `test_substrate_persistence` | 21 | +| **E116** — EPT | `test_ept` | 7 | +| **E120 / E39** — common equip / object service | `test_cem_objects` | 3 | +| **E157** — module process tracking | `test_modules` | 5 | +| **E84** — parallel I/O + timers | `test_e84`, `test_e84_ports`, `test_e84_timers`, `test_e84_asio_timers` | 27 | +| Persistence + cross-cutting | `test_job_persistence`, `test_persistence_upgrade`, `test_wire_ceid_emission`, `test_gem300_scenario`, `test_live_gem300`, `test_thread_safety`, `test_metrics_prometheus`, `test_robustness_fuzz` | 32 | +| **Total** | | **445** | + +A single command to see this live: `docker compose run --rm builder +/app/build/secsgem_tests --list-test-cases | wc -l` (currently 445). + +## What each proof actually demonstrates + +The eight commands above split into four kinds of evidence: + +- **Internal** (#1, #2, #4, #5) — our code testing our code: unit + suite, conformance harness, soak property test, config validator. + Necessary but not independent. +- **External, second implementation** (#3, #7) — round-trip against + secsgem-py 0.3.0 (Python) and secs4java8 (Java). Two independent + SECS implementations must agree with us on every frame. +- **External, third codec** (#6) — Wireshark's HSMS dissector, + written by network-protocol authors who don't share code with + either of us. Catches framing bugs the implementations might both + share. +- **External, structural search** (#8) — libFuzzer + ASan + UBSan + exploring the decoder and SML parser surface for crashes, memory + errors, and UB. + +See [VERIFICATION.md](VERIFICATION.md) for the full test plan and +the rationale for each external validator. diff --git a/README.md b/README.md index 087bd72..eb849ce 100644 --- a/README.md +++ b/README.md @@ -13,67 +13,13 @@ E157**. --- -## Proof of feature-completeness - -"Feature-complete" is a claim that the code must prove, not the -README. These five commands are the proof. If they all exit zero on -a fresh clone, the codebase implements what -[COMPLIANCE.md](COMPLIANCE.md) claims. - -| # | Command | What it proves | -|---|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| -| 1 | `docker compose run --rm tests` | **426 test cases / 2 557 assertions** pass: every store, FSM, codec, parser, persistence path | -| 2 | `docker compose run --rm builder /app/build/secs_conformance --host server --port 5000` | **47 wire-level conformance checks** PASS against a live passive equipment | -| 3 | `docker compose run --rm interop python3 /app/interop/host_vs_cpp_server.py --host server` | **24 interop checks** PASS against secsgem-py 0.3.0 (the Python reference impl) | -| 4 | `SECSGEM_ROBUSTNESS_SOAK=1 docker compose run --rm builder /app/build/secsgem_tests -tc='*soak*'` | **100 000 random tool operations** execute with all invariants and persistence round-trips holding | -| 5 | `docker compose run --rm builder /app/build/secs_server --validate-config --config /app/data/equipment.yaml --state-table /app/data/control_state.yaml --pj-state-table /app/data/process_job_state.yaml --cj-state-table /app/data/control_job_state.yaml` | Every shipped YAML config passes structural + referential validation | -| 6 | `docker compose run --rm builder bash /app/interop/tshark_validate.sh` | **69 HSMS frames** dissected by Wireshark's HSMS dissector (independent third codec) with no malformed packets | -| 7 | `bash interop/secs4j_validate.sh` | **55 cross-validation checks** PASS against [secs4java8](https://github.com/kenta-shimizu/secs4java8) (independent Java implementation), covering S1/S2/S3/S5/S6/S7/S10/S14/S16, the full E40 PJ body, dynamic event reports + unsolicited S6F11 / S5F1 observation, alarm management, spool, PP management, terminal services, limits, trace, E39, and the GEM 300 streams secsgem-py couldn't easily drive | -| 8 | `cmake -B build-fuzz -DSECSGEM_FUZZ=ON && build-fuzz/fuzz_secs2_decode -max_total_time=60` | **~70 000 random inputs** through `secs2::decode`, **~285 000** through `try_parse_sml`, ASan + UBSan + libFuzzer coverage, **0 crashes** | - -Plus, on every push to `main`, [Gitea Actions](.gitea/workflows/ci.yml) -runs both a **Release build + full test suite** and a separate -**ThreadSanitizer lane** that builds with `-fsanitize=thread` and -fails on any race. All 426 cases / 2 557 assertions pass under TSan -clean. - -### Per-standard test coverage - -Every claimed standard has dedicated tests. Counts are -`grep -c TEST_CASE`; cross-cutting tests (e.g. `test_robustness_fuzz`, -`test_gem300_scenario`) exercise multiple standards in concert. - -| Standard | Test files | Cases | -|-----------------------------------|-------------------------------------------------------------------------------------------|------:| -| **E5** — SECS-II encoding | `test_secs2`, `test_sml`, `test_messages`, `test_identifier_wildcards`, `test_fuzz` | 120 | -| **E5 §13** — exceptions | `test_exceptions`, `test_exception_persistence` | 16 | -| **E4** — SECS-I transport | `test_secsi`, `test_secsi_timers`, `test_secsi_tcp` | 27 | -| **E37** — HSMS (SS + GS) | `test_hsms`, `test_hsms_connection`, `test_hsms_timers`, `test_hsms_s9`, `test_hsms_gs`, `test_hsms_gs_integration`, `test_s9_fallback`, `test_concurrency` | 34 | -| **E30** — GEM core | `test_control_state`, `test_communication_state`, `test_host_handler`, `test_data_model`, `test_loader`, `test_config_validate` | 71 | -| **E40** — process jobs | `test_process_jobs` | 21 | -| **E94** — control jobs | `test_control_jobs` | 9 | -| **E42** — formatted PP | `test_e42_formatted_pp` | 6 | -| **E87** — carriers + load ports | `test_carriers`, `test_carrier_state`, `test_carrier_persistence`, `test_e87_wire_scenarios` | 27 | -| **E90** — substrate tracking | `test_substrates`, `test_substrate_persistence` | 21 | -| **E116** — EPT | `test_ept` | 7 | -| **E120 / E39** — common equip / object service | `test_cem_objects` | 3 | -| **E157** — module process tracking | `test_modules` | 5 | -| **E84** — parallel I/O + timers | `test_e84`, `test_e84_ports`, `test_e84_timers`, `test_e84_asio_timers` | 27 | -| Persistence + cross-cutting | `test_job_persistence`, `test_persistence_upgrade`, `test_wire_ceid_emission`, `test_gem300_scenario`, `test_live_gem300`, `test_thread_safety`, `test_metrics_prometheus`, `test_robustness_fuzz` | 32 | -| **Total** | | **426** | - -A single command to see this live: `docker compose run --rm builder -/app/build/secsgem_tests --list-test-cases | wc -l` (currently 426). - ---- - ## Quick start Everything runs in Docker — no compiler or build tools on the host. ```bash docker compose run --rm builder # configure + compile -docker compose run --rm tests # 426 cases / 2 557 assertions +docker compose run --rm tests # 445 cases / 2 753 assertions docker compose up --no-deps server client # live two-container demo ``` @@ -89,9 +35,10 @@ through the data model. Watch the logs interleave. | [COMPLIANCE.md](COMPLIANCE.md) | Per-capability audit against every SEMI standard implemented | | [INTEGRATION.md](INTEGRATION.md) | Vendor-side tutorial: YAML → callbacks → production deploy | | [ARCHITECTURE.md](ARCHITECTURE.md) | How the pieces fit + how to extend (new store / FSM / message) | +| [PROOFS.md](PROOFS.md) | The eight commands that prove the feature-completeness claim | | [VERIFICATION.md](VERIFICATION.md) | Test plan for the external validators behind the proof table | | [BENCHMARKS.md](BENCHMARKS.md) | Performance envelope (throughput, latency, memory) + how to re-run | -| [MES_INTEROP.md](MES_INTEROP.md) | Day-1 punch list to run against your commercial MES (60+ test IDs) | +| [MES_INTEROP.md](MES_INTEROP.md) | Day-1 punch list to run against your commercial MES (59 test IDs) | | [SECURITY.md](SECURITY.md) | Concrete configs: nftables, stunnel, minisign, SIEM audit-log schema | | [GLOSSARY.md](GLOSSARY.md) | SEMI vocabulary: SVID, CEID, PPID, ALCD, HCACK, T-timers, … | | [FAQ.md](FAQ.md) | Common questions and their canonical answers | @@ -100,6 +47,24 @@ through the data model. Watch the logs interleave. --- +## How it's proved + +"Feature-complete" is a claim that the code must prove, not the +README. On a fresh clone, **eight commands** demonstrate it: +unit + integration suite (445 cases / 2 753 assertions), a live +conformance harness (47 wire-level checks), interop against +secsgem-py (31 checks) and secs4java8 (55 checks), a 100 000-op +soak property test, YAML config validation, Wireshark's HSMS +dissector on a recorded pcap (69 frames, 0 malformed), and libFuzzer +(ASan + UBSan, 0 crashes). Each command, exit code, and the +external-vs-internal breakdown live in [PROOFS.md](PROOFS.md). + +CI runs the full suite plus a separate ThreadSanitizer lane on +every push to `main` ([Gitea Actions](.gitea/workflows/ci.yml)); +all 445 cases pass clean under `-fsanitize=thread`. + +--- + ## Architecture The project is **spec-as-data**: the SEMI behavioural rules live in @@ -142,6 +107,9 @@ YAML; the C++ is the engine that reads them. secsgem::metrics Prometheus exporter (Registry + HTTP server). ``` +See [ARCHITECTURE.md](ARCHITECTURE.md) for how to extend it (new +store / FSM / message). + --- ## Adding a capability diff --git a/VERIFICATION.md b/VERIFICATION.md index d288d5d..0ca53d6 100644 --- a/VERIFICATION.md +++ b/VERIFICATION.md @@ -1,13 +1,12 @@ # External verification plan -The five proofs in [README.md](README.md#proof-of-feature-completeness) -are mostly **us testing us**: +The proofs in [PROOFS.md](PROOFS.md) are mostly **us testing us**: | Proof | Independence | |--------------------------------|--------------------------------------------------------------| -| 426 unit/integration tests | Internal — our code testing our code | +| 445 unit/integration tests | Internal — our code testing our code | | 47 conformance harness checks | Internal — our host driving our server | -| 24 secsgem-py interop checks | **External**, but covers ~15–20 % of the claimed wire surface | +| 31 secsgem-py interop checks | **External**, but covers ~15–20 % of the claimed wire surface | | 100 k random tool ops | Internal — property test of our model | | YAML validation | Internal — our validator on our YAML | @@ -273,7 +272,7 @@ After all four: | Proof channel | Independence | |--------------------------------|------------------------------------------------------| -| 426 unit/integration tests | Internal | +| 445 unit/integration tests | Internal | | 47 conformance harness checks | Internal | | **SEMI E5 KAT** | **External — standards body's own encoding rules** | | **tshark dissector** | **External — independent network-protocol authors** | diff --git a/examples/pvd_tool/README.md b/examples/pvd_tool/README.md index 492b19c..4c65386 100644 --- a/examples/pvd_tool/README.md +++ b/examples/pvd_tool/README.md @@ -3,8 +3,8 @@ A fictional Physical Vapor Deposition tool, end-to-end. This is what a real tool integrator's deployment looks like: -- `equipment.yaml` — the tool's data dictionary (32 SVIDs, 5 DVIDs, - 7 ECIDs, 17 CEIDs, 12 alarms, 3 recipes, 9 host commands) +- `equipment.yaml` — the tool's data dictionary (29 SVIDs, 5 DVIDs, + 7 ECIDs, 21 CEIDs, 12 alarms, 3 recipes, 9 host commands) - `main.cpp` — the vendor application: sensor simulator, recipe runner, alarm threshold monitor, EPT cycling, metrics exporter, Router handlers wiring it all to the wire. @@ -21,9 +21,8 @@ customize. They're written to be a template, not an abstract demo. | §3 Recipe runner | Driving a PJ through SettingUp → Processing → ProcessComplete by walking the recipe body, with per-step CEID emission | | §4 Alarm threshold monitor | Continuous threshold-based alarm logic (chamber pressure, cleaning interval) with set/clear emission | | §5 EPT cycling | E116 state transitions driven by PJ state + safety alarms | -| §6 Metrics | Prometheus exporter on `:9090` with per-CEID counters and gauge updates | -| §7 Router handlers | Every SECS/GEM message a host might send to a PVD tool, ~40 handlers in ~200 lines | -| §8 main() | Loading YAML → validating → composing → running | +| §6 Router handlers | Every SECS/GEM message a host might send to a PVD tool, 51 handlers in ~460 lines | +| §7 main() | Loading YAML → validating → composing → running, including the Prometheus exporter on `:9090` (§7.3) | ## Running it @@ -138,7 +137,7 @@ from `main.cpp` directly — each section is independently usable. defined and you'll need them all in production. That's it. No framework, no DI container, no abstract base -classes. ~700 lines of vendor code on top of the library. +classes. ~1,100 lines of vendor code on top of the library. ## Cross-references diff --git a/examples/pvd_tool/main.cpp b/examples/pvd_tool/main.cpp index 99ccab5..11920f2 100644 --- a/examples/pvd_tool/main.cpp +++ b/examples/pvd_tool/main.cpp @@ -10,10 +10,10 @@ // §3. Recipe runner (drives PJ FSM through Processing → Complete) // §4. Alarm threshold monitor (pressure-based) // §5. EPT cycling (Standby ↔ Productive ↔ UnscheduledDowntime) -// §6. Metrics (Prometheus exporter on :9090) -// §7. Router handlers (the minimum set; mostly copied from +// §6. Router handlers (the minimum set; mostly copied from // apps/secs_server.cpp which has the full catalogue) -// §8. main() — wires everything together +// §7. main() — wires everything together, including the +// Prometheus metrics exporter on :9090 (§7.3) // // This file is deliberately self-contained — no pvd_internal/ helper // headers, no factored-out "framework." Customers should be able to diff --git a/interop/README.md b/interop/README.md index ccbaa12..31c2863 100644 --- a/interop/README.md +++ b/interop/README.md @@ -125,8 +125,8 @@ is consistent: non-Python validators). 2. Wired into `.gitea/workflows/ci.yml` as a separate job. 3. Listed in this README's table + in `../VERIFICATION.md`. -4. Surfaced in the README's proof-of-feature-completeness table if - it adds a meaningful new dimension. +4. Surfaced in [`../PROOFS.md`](../PROOFS.md) if it adds a + meaningful new dimension. Bug reports from a new validator → file at `raphael@maenle.net` with the wire trace, the validator's output, diff --git a/interop/tshark_validate.sh b/interop/tshark_validate.sh index ff7d4a3..05e2555 100755 --- a/interop/tshark_validate.sh +++ b/interop/tshark_validate.sh @@ -9,7 +9,10 @@ # both our internal tests and the secsgem-py interop path. # # Usage: tshark_validate.sh [--port PORT] -# Run inside the builder image (which has tshark + tcpdump). +# Run inside the builder image (which has tshark + tcpdump), or on +# any host with tshark + tcpdump installed. Resolves $ROOT from the +# script's own location, so /app/... and any out-of-source checkout +# both work without env overrides. # # Exit codes: # 0 — tshark dissected every HSMS frame without errors @@ -17,9 +20,12 @@ # 2 — script error (binary missing, capture failed, etc.) set -euo pipefail +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) PORT=${PORT:-5099} -SERVER=/app/build/secs_server -CLIENT=/app/build/secs_client +BUILD=${BUILD:-$ROOT/build} +SERVER=${SERVER:-$BUILD/secs_server} +CLIENT=${CLIENT:-$BUILD/secs_client} +DATA=${DATA:-$ROOT/data} [ -x "$SERVER" ] || { echo "FAIL: $SERVER missing — rebuild first"; exit 2; } [ -x "$CLIENT" ] || { echo "FAIL: $CLIENT missing — rebuild first"; exit 2; } @@ -44,10 +50,10 @@ sleep 0.5 echo "starting secs_server on 127.0.0.1:$PORT" $SERVER --port "$PORT" --device 0 \ - --config /app/data/equipment.yaml \ - --state-table /app/data/control_state.yaml \ - --pj-state-table /app/data/process_job_state.yaml \ - --cj-state-table /app/data/control_job_state.yaml \ + --config "$DATA/equipment.yaml" \ + --state-table "$DATA/control_state.yaml" \ + --pj-state-table "$DATA/process_job_state.yaml" \ + --cj-state-table "$DATA/control_job_state.yaml" \ > "$SERVER_LOG" 2>&1 & SERVER_PID=$! sleep 0.5