Ops-dashboard/ops-agent/commands.yml.example
Scrum4Me Agent bdc24b57ba feat(flows): add YAML flow format, flow-runner, and /agent/v1/flow endpoint
- ops-agent/src/lib/flow-runner.ts: loads YAML flows, validates all steps
  against the command whitelist, executes sequentially; supports dry_run
  (emits WOULD RUN lines) and on_failure: abort|continue per step
- ops-agent/src/routes/flow.ts: POST /agent/v1/flow { flow_key, dry_run }
  streams step_start/stdout/stderr/step_done/done SSE events
- ops-agent/src/index.ts: register flow route, add FLOWS_PATH env var
- ops-agent/flows.example/: three flow definitions — update_scrum4me_web,
  update_mcp_worker, update_caddy_config; deploy to /etc/ops-agent/flows/
- ops-agent/commands.yml.example: add curl_smoke_scrum4me_web and
  docker_compose_ps_worker smoke-test commands
- app/api/flows/run/route.ts: Next.js proxy — creates FlowRun/FlowStep
  DB records per step, forwards SSE stream to browser
- hooks/useFlowRun.ts: add startFlow(flowKey, dryRun) method; handle
  step_start events to display step headers in the terminal
- components/StreamingTerminal.tsx: add 'info' line type (sky-400) for
  step headers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 19:22:34 +02:00

164 lines
5.5 KiB
Text

# Whitelist of allowed commands for ops-agent.
# Copy to /etc/ops-agent/commands.yml on the host.
# Restart ops-agent after changes.
#
# Schema per command:
# cmd: required — command + static args as array (no shell, no interpolation)
# cwd: optional — working directory for the subprocess
# cwd_pattern: optional — working directory as a glob/pattern (resolved at runtime)
# args:
# allowed: optional — whitelist of argument values accepted from the caller
# If absent or empty, the command takes no extra arguments.
# description: optional — human-readable description
commands:
docker_ps:
cmd: ["docker", "ps", "--format", "table"]
description: "List running Docker containers"
git_status:
cmd: ["git", "status", "--short", "--branch"]
cwd_pattern: "/srv/"
description: "Git status with branch info (first arg = repo path, must start with /srv/)"
git_log_ahead:
cmd: ["git", "log", "@{upstream}..HEAD", "--oneline"]
cwd_pattern: "/srv/"
description: "Local commits not yet pushed (first arg = repo path)"
git_diff:
cmd: ["git", "diff", "HEAD"]
cwd_pattern: "/srv/"
description: "Uncommitted diff against HEAD (first arg = repo path)"
git_fetch:
cmd: ["git", "fetch", "--quiet"]
cwd_pattern: "/srv/"
description: "Fetch all remotes silently (first arg = repo path)"
systemctl_status:
cmd: ["systemctl", "status", "--no-pager", "-l"]
args:
allowed:
- scrum4me-web
- ops-agent
- caddy
- docker
- nginx
- postgresql
description: "Show systemctl status for an allowed service"
journalctl_recent:
cmd: ["journalctl", "--since", "1 hour ago", "-n", "100", "--no-pager", "-u"]
args:
allowed:
- scrum4me-web
- ops-agent
- caddy
- docker
- nginx
- postgresql
description: "Last 100 journal lines from the past hour for an allowed service"
caddy_show_config:
cmd: ["caddy", "fmt", "/etc/caddy/Caddyfile"]
description: "Print the formatted Caddy config"
caddy_list_certs:
cmd:
- sh
- -c
- "for f in /data/caddy/certificates/*/*.crt; do [ -f \"$f\" ] || continue; echo \"CERTFILE:$f\"; openssl x509 -noout -subject -issuer -dates -in \"$f\" 2>&1; echo \"CERTEND\"; done"
description: "List TLS cert info (subject, issuer, validity dates) from Caddy certificate store"
# ── Destructive / write commands ──────────────────────────────────────────
docker_compose_restart:
cmd: ["docker", "compose", "restart"]
cwd: "/srv/scrum4me/compose"
args:
allowed:
- scrum4me-web
- worker-idea
- ops-dashboard
- caddy
- postgres
description: "Restart a docker compose service (ops-agent user must be in the docker group)"
docker_compose_stop:
cmd: ["docker", "compose", "stop"]
cwd: "/srv/scrum4me/compose"
args:
allowed:
- scrum4me-web
- worker-idea
- ops-dashboard
- caddy
- postgres
description: "Stop a docker compose service"
docker_compose_build:
cmd: ["docker", "compose", "build"]
cwd: "/srv/scrum4me/compose"
args:
allowed:
- scrum4me-web
- worker-idea
- ops-dashboard
description: "Build a docker compose service image"
docker_compose_up:
cmd: ["docker", "compose", "up", "-d"]
cwd: "/srv/scrum4me/compose"
args:
allowed:
- scrum4me-web
- worker-idea
- ops-dashboard
description: "Start or recreate a docker compose service in detached mode"
git_pull:
cmd: ["git", "pull", "--ff-only"]
cwd_pattern: "/srv/"
preconditions:
- git_status_clean
description: "Fast-forward pull — refused when working tree is dirty"
systemctl_restart:
# Requires /etc/sudoers.d/ops-agent (see deploy/ops-agent/sudoers).
cmd: ["sudo", "/usr/bin/systemctl", "restart"]
args:
allowed:
- scrum4me-web
- ops-agent
- caddy
description: "Restart an allowed systemd service via sudo"
caddy_validate:
cmd: ["caddy", "validate", "--config", "/srv/scrum4me/caddy/Caddyfile"]
description: "Validate /srv/scrum4me/caddy/Caddyfile without reloading"
caddy_reload:
cmd: ["caddy", "reload", "--config", "/srv/scrum4me/caddy/Caddyfile"]
description: "Reload Caddy with /srv/scrum4me/caddy/Caddyfile"
caddy_write_config:
# Writes stdin to Caddyfile.new first; mv is atomic on the same filesystem.
# ops-agent user must own /srv/scrum4me/caddy/.
cmd:
- sh
- -c
- "cat > /srv/scrum4me/caddy/Caddyfile.new && mv /srv/scrum4me/caddy/Caddyfile.new /srv/scrum4me/caddy/Caddyfile"
stdin_from_body: true
description: "Atomically replace /srv/scrum4me/caddy/Caddyfile (write stdin to .new, then mv)"
# ── Smoke tests / health checks ───────────────────────────────────────────
curl_smoke_scrum4me_web:
cmd: ["curl", "-sf", "--max-time", "10", "https://scrum4me.com"]
description: "HTTP smoke test — fails (non-zero) if the site is unreachable or returns a non-2xx status"
docker_compose_ps_worker:
cmd: ["docker", "compose", "ps", "--filter", "status=running", "worker-idea"]
cwd: "/srv/scrum4me/compose"
description: "Verify worker-idea container is in the running state"