- Remove sudo fallbacks from telegram-commands.ts and channels/telegram.ts - Refactor startup-report.ts to accept pre-fetched hostd data (async path) - Add bastille-destroy hostd op to privileged-commands.ts - Strip TTS/STT/vision/chat-policy/model-catalog from index.ts - Add scripts/hostd-call.sh for shell script -> hostd communication - Remaining runtime sudo: startup-report sync fallback (lines 847-850) --- Build: pass | Tests: n/a (Linux agent, 3 pre-existing controlplane-db errors) --- Build: FAIL | Tests: FAIL — 16 failed
119 lines
4.1 KiB
Bash
Executable file
119 lines
4.1 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# hostd-call.sh — Call the hostd Unix socket API from POSIX sh.
|
|
#
|
|
# Lets shell scripts invoke privileged operations (bastille, zfs, etc.)
|
|
# through the hostd daemon without needing sudo or Node.js.
|
|
#
|
|
# Usage: hostd-call.sh <op> [json-params]
|
|
# op Operation name (e.g. "bastille-list", "zfs-snapshot")
|
|
# json-params Optional JSON object for params (e.g. '{"jail":"db"}')
|
|
#
|
|
# Environment:
|
|
# HOSTD_SOCKET Socket path (default: /var/run/clawdie-hostd.sock)
|
|
# HOSTD_TOKEN Auth token (overrides env/file lookup)
|
|
# CONTROLPLANE_SHARED_SECRET Shared secret (same as Node.js runtime)
|
|
# HOSTD_TOKEN_FILE Token file (default: ~/.config/clawdie/hostd-token)
|
|
#
|
|
# Examples:
|
|
# hostd-call.sh bastille-list
|
|
# hostd-call.sh bastille-start '{"jail":"db"}'
|
|
# hostd-call.sh zfs-snapshot '{"dataset":"zroot/data","name":"pre-deploy"}'
|
|
|
|
set -e
|
|
|
|
op="${1:?Usage: hostd-call.sh <op> [json-params]}"
|
|
params="$2"
|
|
: "${params:={}}"
|
|
|
|
socket="${HOSTD_SOCKET:-/var/run/clawdie-hostd.sock}"
|
|
token_file="${HOSTD_TOKEN_FILE:-$HOME/.config/clawdie/hostd-token}"
|
|
|
|
if [ -n "${HOSTD_TOKEN:-}" ]; then
|
|
token="$HOSTD_TOKEN"
|
|
elif [ -n "${CONTROLPLANE_SHARED_SECRET:-}" ]; then
|
|
token="$CONTROLPLANE_SHARED_SECRET"
|
|
elif [ -r "$token_file" ]; then
|
|
token=$(cat "$token_file")
|
|
else
|
|
echo "hostd-call: no auth token — set HOSTD_TOKEN, CONTROLPLANE_SHARED_SECRET, or create $token_file" >&2
|
|
exit 1
|
|
fi
|
|
|
|
token=$(printf '%s' "$token" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
|
|
if command -v uuidgen >/dev/null 2>&1; then
|
|
id=$(uuidgen)
|
|
elif [ -r /proc/sys/kernel/random/uuid ]; then
|
|
id=$(cat /proc/sys/kernel/random/uuid)
|
|
else
|
|
id="hostd-$(date +%s)-$$"
|
|
fi
|
|
|
|
token_esc=$(printf '%s' "$token" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
op_esc=$(printf '%s' "$op" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
|
|
request=$(printf '{"id":"%s","op":"%s","params":%s,"auth":{"token":"%s","caller":"operator","tenantId":""}}' \
|
|
"$id" "$op_esc" "$params" "$token_esc")
|
|
|
|
if command -v nc >/dev/null 2>&1; then
|
|
response=$(printf '%s\n' "$request" | nc -U -w 10 "$socket" 2>/dev/null) || true
|
|
elif command -v node >/dev/null 2>&1; then
|
|
response=$(printf '%s\n' "$request" | HOSTD_SOCKET_PATH="$socket" node -e '
|
|
var net=require("net"),fs=require("fs"),b="";
|
|
var c=net.connect(process.env.HOSTD_SOCKET_PATH);
|
|
c.on("connect",function(){c.write(fs.readFileSync("/dev/stdin","utf8"));});
|
|
c.on("data",function(d){b+=d.toString();if(b.indexOf("\n")>=0){process.stdout.write(b);c.destroy();process.exit(0);}});
|
|
setTimeout(function(){if(b)process.stdout.write(b);process.exit(1);},10000);
|
|
' 2>/dev/null) || true
|
|
else
|
|
echo "hostd-call: need nc or node to connect to Unix socket" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$response" ]; then
|
|
echo "hostd-call: no response from $socket (is hostd running?)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
printf '%s\n' "$response" | awk '
|
|
function jstr(s, key, idx,rest,val,c,nc,i) {
|
|
idx = index(s, "\"" key "\"")
|
|
if (!idx) return ""
|
|
rest = substr(s, idx + length(key) + 2)
|
|
sub(/^[[:space:]]*:[[:space:]]*/, "", rest)
|
|
if (substr(rest,1,1) != "\"") return ""
|
|
rest = substr(rest, 2)
|
|
val = ""
|
|
for (i = 1; i <= length(rest); i++) {
|
|
c = substr(rest, i, 1)
|
|
if (c == "\\" && i < length(rest)) {
|
|
nc = substr(rest, i+1, 1)
|
|
if (nc == "n") { val = val "\n"; i++; continue }
|
|
if (nc == "t") { val = val "\t"; i++; continue }
|
|
if (nc == "r") { val = val "\r"; i++; continue }
|
|
if (nc == "\\") { val = val "\\"; i++; continue }
|
|
if (nc == "\"") { val = val "\""; i++; continue }
|
|
if (nc == "/") { val = val "/"; i++; continue }
|
|
val = val nc; i++; continue
|
|
}
|
|
if (c == "\"") return val
|
|
val = val c
|
|
}
|
|
return val
|
|
}
|
|
{
|
|
ok = (match($0, /"ok"[[:space:]]*:[[:space:]]*true/) > 0)
|
|
out = jstr($0, "output")
|
|
err = jstr($0, "error")
|
|
|
|
if (ok) {
|
|
if (out != "") printf "%s\n", out
|
|
exit 0
|
|
} else {
|
|
if (err != "") printf "%s\n", err > "/dev/stderr"
|
|
else if (out != "") printf "%s\n", out > "/dev/stderr"
|
|
else printf "hostd-call: unknown error\n" > "/dev/stderr"
|
|
exit 1
|
|
}
|
|
}'
|