HIL Orchestration¶
Use run_external when you already own a simulator or HIL rig and want BenchCI to trigger it from CI, collect its reports, and preserve the results in normal BenchCI evidence.
BenchCI v1 does not include vendor-native adapters for dSPACE, NI VeriStand, Vector CANoe, Speedgoat, ASAM XIL, ControlDesk, CANoe COM automation, or Windows/.NET APIs. The supported integration surface is deliberately simple:
run a bench-owner-approved wrapper command on the Agent, or
call an allow-listed HTTP API and poll for completion.
The wrapper or HTTP service talks to the rig you already operate.
Bench policy¶
External orchestration is denied by default. The bench owner must opt in and define targets under safety.external.
safety:
external:
enabled: true
targets:
canoe_smoke:
work_root: /opt/benchci/external/canoe
output_root: /opt/benchci/external/canoe/out
argv_prefix:
- /opt/benchci/wrappers/run-canoe-smoke
arg_patterns:
- "[A-Za-z0-9_.-]+"
max_timeout_ms: 1800000
max_logs: 20
max_log_bytes: 262144
max_log_total_bytes: 1048576
max_artifacts: 50
max_artifact_bytes: 1048576
max_artifact_total_bytes: 5242880
lock_key: external:canoe-rig-1
argv_prefix is controlled by bench.yaml. Suite authors can only append args; they cannot replace the command prefix.
Prefer a wrapper that accepts a small positional argument set. Avoid bare prefixes such as ssh hil@host or curl because suite args could become tool options. For an SSH-to-Windows rig, make the wrapper own the SSH command, fixed options, remote script path, and copy-back behavior.
Suite step¶
tests:
- name: canoe HIL smoke
steps:
- run_external:
target: canoe_smoke
cwd: runs/pr-142
args: ["smoke"]
timeout_ms: 900000
source: canoe
framework: hil
junit: reports/junit.xml
logs:
- logs/canoe.log
artifacts:
- captures
All suite-controlled local paths are relative. BenchCI rejects absolute paths, .. traversal, and symlinks that resolve outside the allowed collection root.
HTTP targets¶
HTTP targets must define base_url. BenchCI enforces the base URL for both trigger and poll requests, disables redirects, fails on 3xx, URL-encodes {job_id}, and redacts header values in evidence.
safety:
external:
enabled: true
targets:
rig_api:
work_root: /opt/benchci/external/rig-api
base_url: http://rig-controller.local/api
methods: [POST, GET]
max_poll_interval_ms: 10000
- run_external:
target: rig_api
timeout_ms: 600000
http:
method: POST
url: runs
headers_env:
Authorization: RIG_API_AUTH
json:
suite: smoke
job_id_json_path: job_id
poll:
method: GET
url: runs/{job_id}
interval_ms: 1000
status_json_path: status
success_values: [passed]
failure_values: [failed, error]
junit: reports/junit.xml
poll.interval_ms must be at least 500 ms.
Agent-local collection¶
Collection is Agent-local. After the trigger finishes, BenchCI reads JUnit, CTRF, logs, and artifacts from the Agent filesystem.
For a Windows HIL host reached over SSH, the wrapper must copy reports and artifacts back to the Agent before it exits. A common pattern is:
Agent wrapper creates an Agent-local run directory.
Wrapper triggers the Windows host over SSH or HTTP.
Windows-side script writes JUnit/CTRF and captures.
Wrapper copies those files back to the Agent run directory.
Wrapper exits only after copy-back is complete.
Evidence¶
BenchCI writes external-results.json, adds evidence.external_results, merges parsed external tests into evidence.traceability.tests, and records the exact effective command argv or HTTP method/URL with headers redacted.
The step fails when declared reports are missing, parsing fails, reports contain zero tests, parsed tests include failed/error statuses, a command exits nonzero, HTTP reports failure, or the timeout is reached.
Locking boundary¶
External targets use BenchCI resource locks. By default, target canoe_smoke locks external:canoe_smoke; set lock_key when multiple targets address the same rig.
Locks are per Agent host in v1. If one physical rig is reachable from two different Agents, BenchCI does not serialize across those Agents. Use one physical rig with one Agent, or route all triggers for that rig through a single Agent-controlled target.
Artifact caps¶
Agent-side caps are enforced before files are read and uploaded. Defaults mirror the external-result API limits. Bench policy can raise per-target caps for real HIL captures, bounded by the backend deployment’s configured hard limits.