CyberCLI

← All engines · Delivery

Local command adapter

stable

v1.0.0 · last updated 2026-06-06 · source: cybercli.delivery.channels.local_command

§1

What it does

Operator-supplied script invoked with the sanitized JSON payload on stdin — the universal escape hatch for any local action that doesn't fit a HTTP-shaped adapter (siren, light, GPIO, legacy syslog forwarder, etc.).

§2

Why you care

Some installs need to do things to physical hardware on alert. Trigger a UPS to start logging. Turn a light strip red. Cut audio to a secure room. Write to a serial port. The LocalCommandAdapter is the engine's way to wire that without inventing a per-hardware adapter.

The script runs as the engine's uid, with the sanitized payload on stdin (no shell interpolation, no quoting bugs). Output goes to the audit row's `parameters.script_stdout` (truncated at 4KB). Exit code 0 = success; non-zero = failure with the code on the audit row.

§3

How it works

On dispatch the adapter resolves the configured script path, validates it exists + is executable, then runs `subprocess.run([path], stdin=PIPE, stdout=PIPE, stderr=PIPE, timeout=30)` with the sanitized payload as stdin. The 30-second timeout is hard; long-running scripts are killed and the failure surfaces with `timed_out: true`.

Payload sanitization runs through the dispatcher's standard sanitizer — no shell-special characters in the body, no log-injection escapes, no truncated-secret leaks. The script can trust its stdin to be clean JSON.

§4

Configure & observe

CLI

$ cybercli channels test <destination_id>

Invoke the script with a synthetic payload; verify the exit code is 0 and the script's stdout is in the audit row.

Dashboard surfaces

/channels (local-command card)

Configure the script path + optional env vars. The path must exist + be executable at validation time.

Audit row shape

Outcomes emitted
notification_sentnotification_failed
Parameters block

parameters.channel: local_command + parameters.script_path + parameters.exit_code + parameters.script_stdout (truncated 4KB) + parameters.timed_out: true|false.

§5

Status

Stable — the subprocess + timeout + sanitizer flow is unchanged since 2026-05-08. The acceptance install on LXC 200 uses this adapter for a 'tail to a file' script as the basic smoke-test of the framework.

Known limit: the script must complete in 30s. Long-running side effects (e.g. a 5-minute SIEM ingest job) should be fire-and-forget within the script itself (background the work, return quickly) — the engine deliberately doesn't wait that long for an alert path.

How this engine talks to the rest

Upstream · feeds this engine
Downstream · this engine feeds