DEV Community

Run AI-Proposed Shell Commands in a systemd Probe Before You Run Them for Real

Disclosure: This article was prepared as part of MonkeyCode's product outreach. A free model can produce shell commands that are syntactically valid but operationally unsafe, and the free server option gives you somewhere to stage them. The problem is not whether the command parses; it is whether the command's observable effect matches the intent.

Why a command string needs a different gate

bash -n and ShellCheck catch syntax and common mistakes, but they do not know the runtime context of your server. A command such as docker compose up -d --remove-orphans may be valid on a workstation but may pull new images, expose ports, or use the wrong Compose file on the server. Generated commands are often written from generic knowledge, without the local usernames, mount points, and firewall rules.

The gate in this article runs the proposed command in a short-lived systemd service with a read-only system tree, no new privileges, restricted devices, and bounded memory and runtime. It records stdout, stderr, and exit code in a JSON artifact, then compares the result to a declared expectation before the command is allowed anywhere near a real shell.

The probe contract

Define four values for each generated command:

  • COMMAND - the exact string from the model.
  • EXPECT_RC - the exit code you want, usually 0.
  • EXPECT_MARKER - a literal substring that must appear in stdout, or empty for none.
  • ALLOW_WRITE_DIR - optional path if the command needs write access, added as ReadWritePaths=.

Separating the command from the expected observable effect prevents "it exited zero" from hiding a command that wrote no output but did something else.

Reusable probe script

Save the following as probe_cmd.sh and make it executable. It uses systemd-run under sudo; change RuntimeMaxSec=12 and MemoryMax=64M for longer checks.

#!/usr/bin/env bash
set -uo pipefail

PROPOSED_CMD="${1:?usage: probe_cmd.sh 'command'}"
EXPECT_RC="${EXPECT_RC:-0}"
EXPECT_MARKER="${EXPECT_MARKER:-}"
ALLOW_WRITE_DIR="${ALLOW_WRITE_DIR:-}"
EVIDENCE_DIR="${EVIDENCE_DIR:-/var/tmp/ai-probes}"

PROBE_ID="ai-probe-$(date +%s)-$$"
mkdir -p "$EVIDENCE_DIR"
out_file="$EVIDENCE_DIR/$PROBE_ID.out"
err_file="$EVIDENCE_DIR/$PROBE_ID.err"
log_file="$EVIDENCE_DIR/$PROBE_ID.json"

extra_props=()
if [[ -n "$ALLOW_WRITE_DIR" ]]; then
  extra_props+=(--property="ReadWritePaths=$ALLOW_WRITE_DIR")
fi

sudo systemd-run --wait --pipe --quiet --property=User=nobody --property=NoNewPrivileges=yes --property=ProtectSystem=strict --property=ProtectHome=read-only --property=PrivateTmp=yes --property=PrivateDevices=yes --property=MemoryMax=64M --property=RuntimeMaxSec=12 "${extra_props[@]}" bash -lc "$PROPOSED_CMD" > "$out_file" 2> "$err_file"
rc=$?

marker_ok=0
if [[ -z "$EXPECT_MARKER" ]]; then
  marker_ok=1
elif grep -qF -- "$EXPECT_MARKER" "$out_file"; then
  marker_ok=1
fi

jq -n --arg id "$PROBE_ID" --arg cmd "$PROPOSED_CMD" --arg expected_rc "$EXPECT_RC" --arg rc "$rc" --arg expected_marker "$EXPECT_MARKER" --arg marker_ok "$marker_ok" --arg stdout "$(cat "$out_file")" --arg stderr "$(cat "$err_file")" '{probe_id:$id, command:$cmd, expected_exit:($expected_rc|tonumber), observed_exit:($rc|tonumber), expected_marker:$expected_marker, marker_satisfied:($marker_ok|tonumber), stdout:$stdout, stderr:$stderr}' > "$log_file"

pass=1
if [[ "$rc" -ne "$EXPECT_RC" ]]; then
  pass=0
fi
if [[ -n "$EXPECT_MARKER" && "$marker_ok" -ne 1 ]]; then
  pass=0
fi

if [[ "$pass" -ne 1 ]]; then
  echo "probe failed: $log_file" >&2
  exit 1
fi
echo "probe passed: $
Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.