#!/bin/bash # ===================================================================== # What the sub-agent container can and cannot reach. # # ./tests/vm_agent_asserts.sh # # WHY THIS IS A SEPARATE BOUNDARY FROM THE GUEST'S # # The VM's isolation is about code somebody else wrote. This one is about # OUR code, and it exists because of two specific things on the other # side of it: # # Ollama has no authentication at all, and serves DELETE /api/delete, # POST /api/pull and POST /api/create. Anything that can reach # 172.17.0.1:11434 can delete the model the whole assistant runs on. # # The Open WebUI key has to be an ADMIN key, because anyone may invoke # vm_agent and the chat belongs to whoever is talking. An admin key in # the agent container would be an agent that can read every # conversation on this instance. # # So the agent reaches exactly one address, and the thing at that address # exposes exactly three URLs. This checks both halves. # ===================================================================== set -uo pipefail AGENT=owuitools-vmagent GW=172.22.2.10:8000 fails=0 ok() { printf ' ok %s\n' "$*"; } bad() { printf ' FAIL %s\n' "$*"; fails=$((fails+1)); } docker inspect "$AGENT" >/dev/null 2>&1 || { echo "$AGENT is not running" >&2; exit 1; } echo "== 1. the agent reaches vmgw, and nothing else" probe=$(docker exec -i "$AGENT" python3 - <<'PY' import socket def p(h, port): try: socket.create_connection((h, port), 3).close(); return "REACHED" except Exception: return "blocked" for h, port, name in [("172.22.2.10", 8000, "vmgw"), ("172.17.0.1", 11434, "ollama-direct"), ("172.19.0.2", 8080, "openwebui-direct"), ("192.168.1.10", 7200, "gitea-lan"), ("192.168.1.10", 22, "host-sshd"), ("192.168.1.1", 80, "lan-gateway"), ("1.1.1.1", 443, "internet")]: print(name, p(h, port)) PY ) while read -r name verdict; do [ -z "$name" ] && continue if [ "$name" = "vmgw" ]; then [ "$verdict" = "REACHED" ] && ok "vmgw is reachable (positive control)" \ || bad "vmgw is NOT reachable - this suite proves nothing" else [ "$verdict" = "blocked" ] && ok "$name is blocked" || bad "$name was REACHABLE" fi done <<< "$probe" echo echo "== 2. vmgw exposes two URLs and refuses everything else" paths=$(docker exec -i "$AGENT" python3 - </dev/null || true) if printf '%s' "$gw_env" | grep -q '^OWUITOOLS_OWUI_API_KEY=.'; then bad "owuitools-vmgw still holds an Open WebUI API key" else ok "owuitools-vmgw holds no Open WebUI API key" fi # A proxy_pass, not a mention: the config's own header explains what used # to be here, and matching that comment reported the opposite of the truth. if docker exec owuitools-vmgw grep -rqE '^[^#]*proxy_pass.*chats' /etc/nginx/conf.d/ 2>/dev/null; then bad "owuitools-vmgw still proxies the Open WebUI event endpoint" else ok "owuitools-vmgw does not proxy the Open WebUI event endpoint" fi env_dump=$(docker exec "$AGENT" env 2>/dev/null || true) for secret in OWUITOOLS_OWUI_API_KEY GITEA_TOKEN OWUITOOLS_AUTH_TOKEN; do if printf '%s' "$env_dump" | grep -q "^${secret}=."; then bad "$secret is in the agent's environment" else ok "$secret is not in the agent's environment" fi done # vmd's config holds the Gitea token and is 0640 root:owuivmd. if docker exec "$AGENT" test -r /etc/owuivm/vmd.env 2>/dev/null; then bad "the agent can read vmd's credential file" else ok "the agent cannot read vmd's credential file" fi echo if [ "$fails" -gt 0 ]; then echo "FAILED $fails"; exit 1; fi echo "the agent container is confined as designed"