colibri/packaging/mother/colibri-mcp-ssh
Sam & Claude 7b3e757817 feat(mother): idempotent MCP setup, injection-proof node-register, hardened wrapper + builder
Consolidates mother MCP infrastructure into packaging/mother/:

- setup-mother.sh: idempotent deploy script (binaries, MCP tools, SSH keys,
  PostgreSQL peer auth, jq-merge external-mcp.json, daemon env update)
- node-register-mcp: UPSERT hw-probe JSON into mother_hive.usb_nodes
  using psql -v :variable heredoc (bound parameter, no SQL interpolation)
- colibri-mcp-ssh: SSH forced-command wrapper with allowlist
  (only "" → stdio MCP mode, "tools" → discovery; everything else rejected)
- build-colibri.sh: branch-allowlisted builder (main + semver tags +
  COLIBRI_BUILD_ALLOW_BRANCHES), features validated, array-quoted cargo args
- MOTHER-SETUP.md: architecture document with security properties

Security fixes vs. the clawdie-iso versions:
- node-register-mcp: was E${ESCAPED} (vulnerable to E backslash
  interpretation); now psql -v :variable in a heredoc
- colibri-mcp-ssh: was unquoted ${SSH_ORIGINAL_COMMAND} passthrough;
  now case-match allowlist
- build-colibri.sh: was arbitrary git checkout + unquoted cargo flags;
  now branch allowlist + features validation + array args
- USB spawn args: no trailing "colibri-mcp" remote command;
  forced-command wrapper handles empty command
- Key management: one key per trust domain (mother-mcp != Forgejo);
  key lives on seed partition, not baked into image
2026-06-24 09:31:04 +02:00

32 lines
1.1 KiB
Bash
Executable file

#!/bin/sh
# SSH forced-command wrapper for mother MCP entrypoint.
#
# SSH's authorized_keys command="..." restriction replaces the client's
# command with this script and stores the original in $SSH_ORIGINAL_COMMAND.
#
# Allowlist:
# "" → colibri-mcp in stdio MCP mode (persistent JSON-RPC channel)
# "tools" → colibri-mcp tools (one-shot discovery, debugging)
# everything else → rejected with exit 1
#
# Why: the wrapper's job is to constrain what callers can do through the
# SSH forced-command boundary. Without an allowlist, the caller can pass
# any colibri-mcp subcommand or flag — including ones not yet written.
#
# Installed by setup-mother.sh into /usr/local/bin/.
# Referenced from: ~/.ssh/authorized_keys command="/usr/local/bin/colibri-mcp-ssh"
set -eu
case "${SSH_ORIGINAL_COMMAND:-}" in
"")
exec /usr/local/bin/colibri-mcp
;;
"tools")
exec /usr/local/bin/colibri-mcp tools
;;
*)
printf '{"jsonrpc":"2.0","id":null,"error":{"code":-1,"message":"rejected: %s"}}\n' \
"$(printf '%s' "${SSH_ORIGINAL_COMMAND}" | sed 's/"/\\"/g')" >&2
exit 1
;;
esac