7d8c411f5c
Variante A endlich umgesetzt: echter Hard-Block vor Bash-Ausfuehrung.
Anders als 14 seed_rules + Bypass-Lehre, die ARIA ignorieren kann,
ist das ein technisch erzwungener Reject auf claude-CLI-Ebene.
Komponenten:
1. aria-brain main.py: neuer Endpoint POST /skills/can-bash-host
Bekommt {command}, parst https-URLs raus, prueft gegen aktive Skills
(stem-match: 'spotify' im Hostname 'api.spotify.com'). Returnt
{block, host, skill, safe_tool} wenn ein Skill den Host abdeckt.
2. proxy-patches/pre-tool-bash-block.js: Node-Script das vom claude-CLI
als PreToolUse-Hook fuer das Bash-Tool aufgerufen wird. Liest Tool-
Use-Payload via stdin, ruft Brain-Endpoint mit kurzem Timeout (3s),
bei block=true → exit 2 mit Stderr-Message. claude-CLI gibt Stderr
als tool_use_error an das LLM zurueck — echter Fehler, nicht
ignorierbar.
Fail-open bei Brain-Down / Timeout / JSON-Fehler: kein Lockout.
3. proxy-patches/managed-settings.json: claude-CLI Hook-Config mit
PreToolUse-Matcher 'Bash' der das Node-Script ausfuehrt.
/etc/claude-code/managed-settings.json hat Vorrang vor User-Settings
und betrifft NICHT Stefans Host-~/.claude/settings.json.
4. docker-compose.yml: proxy-Command erweitert um
`mkdir -p /etc/claude-code && cp managed-settings.json dorthin`
damit beim Container-Start die Hook-Config aktiv ist.
Beobachtung die das motiviert: 14 seed_rules + Bypass-Lehre +
Auto-Scaffold + Safe-Names. ARIA hat trotzdem letzten Test mit 2
verschachtelten Bash-curls bedient statt run_spotify zu rufen
(content_len=73, tool_calls=0). Prompt-Engineering ausgereizt.
ARIA bekommt jetzt:
🚨 BASH GEGEN api.spotify.com BLOCKIERT.
Es existiert bereits ein Skill 'spotify' fuer diesen Host. ...
Konkret: nutze JETZT `run_spotify` mit den passenden Parametern
(method/path/body) statt curl.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
156 lines
7.2 KiB
YAML
156 lines
7.2 KiB
YAML
services:
|
|
|
|
# ─── Claude Max API Proxy ───────────────────────────────
|
|
proxy:
|
|
image: node:22-alpine
|
|
container_name: aria-proxy
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway" # Zugriff auf die VM via SSH
|
|
command: >-
|
|
sh -c "apk add --no-cache openssh-client bash curl &&
|
|
npm install -g @anthropic-ai/claude-code claude-max-api-proxy &&
|
|
DIST=$$(find /usr/local/lib -path '*/claude-max-api-proxy/dist' -type d | head -1) &&
|
|
sed -i 's/startServer({ port })/startServer({ port, host: process.env.HOST || \"127.0.0.1\" })/' $$DIST/server/standalone.js &&
|
|
sed -i 's/\"--no-session-persistence\",/\"--no-session-persistence\",\"--dangerously-skip-permissions\",/' $$DIST/subprocess/manager.js &&
|
|
sed -i 's/const DEFAULT_TIMEOUT = 300000;/const DEFAULT_TIMEOUT = 86400000;/' $$DIST/subprocess/manager.js &&
|
|
cp /proxy-patches/openai-to-cli.js $$DIST/adapter/openai-to-cli.js &&
|
|
cp /proxy-patches/cli-to-openai.js $$DIST/adapter/cli-to-openai.js &&
|
|
cp /proxy-patches/routes.js $$DIST/server/routes.js &&
|
|
mkdir -p /etc/claude-code &&
|
|
cp /proxy-patches/managed-settings.json /etc/claude-code/managed-settings.json &&
|
|
claude-max-api"
|
|
volumes:
|
|
- ~/.claude:/root/.claude # Claude CLI Auth (Credentials in /root/.claude/.credentials.json)
|
|
- ./aria-data/ssh:/root/.ssh # SSH Keys fuer VM-Zugriff (aria-wohnung, rw fuer ARIA)
|
|
- aria-shared:/shared # Shared Volume fuer Datei-Austausch (Uploads von App)
|
|
- ./proxy-patches:/proxy-patches:ro # Tool-Use-Adapter (ueberschreibt npm-Version, read-only)
|
|
# Claude Code's eingebautes Auto-Memory liegt in ~/.claude/projects/.
|
|
# Wir ueberlagern das mit tmpfs damit ARIA nicht parallel zu ARIAs eigener
|
|
# Qdrant-DB ein File-Memory aufbaut (war Auslöser fuer doppelte Truth-Source).
|
|
# Tmpfs ist beim Container-Start leer und wird beim Container-Recreate
|
|
# weggeworfen — Claude Code sieht keine alten Files mehr und das was sie
|
|
# ggf. neu schreibt landet nicht auf dem VM-Host.
|
|
tmpfs:
|
|
- /root/.claude/projects
|
|
environment:
|
|
- HOST=0.0.0.0
|
|
- SHELL=/bin/bash # Claude Code Bash-Tool braucht bash (nicht nur sh/ash)
|
|
- CLAUDE_CODE_BUBBLEWRAP=1 # Erlaubt --dangerously-skip-permissions als root
|
|
restart: unless-stopped
|
|
networks:
|
|
- aria-net
|
|
|
|
# ─── Qdrant (Vector-DB fuer ARIAs Gedaechtnis) ────────
|
|
# Storage liegt im Repo-Bind-Mount aria-data/brain/qdrant.
|
|
# Damit Backup/Export/Import komplett ueber das Filesystem gehen.
|
|
qdrant:
|
|
image: qdrant/qdrant:latest
|
|
container_name: aria-qdrant
|
|
volumes:
|
|
- ./aria-data/brain/qdrant:/qdrant/storage
|
|
restart: unless-stopped
|
|
networks:
|
|
- aria-net
|
|
|
|
# ─── ARIA Brain (Agent + Memory) ─────────────────────────
|
|
# Loest das alte aria-core (OpenClaw) ab. Vector-DB-basiertes
|
|
# Memory, eigener Agent-Loop, SSH zur aria-wohnung-VM.
|
|
brain:
|
|
build: ./aria-brain
|
|
container_name: aria-brain
|
|
hostname: aria-wohnung-brain # damit ssh known_hosts stabil bleibt
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway" # Zugriff auf die VM via SSH
|
|
depends_on:
|
|
- qdrant
|
|
- proxy
|
|
environment:
|
|
- QDRANT_HOST=aria-qdrant
|
|
- QDRANT_PORT=6333
|
|
- PROXY_URL=http://proxy:3456
|
|
- ARIA_AUTH_TOKEN=${ARIA_AUTH_TOKEN:-}
|
|
# Read-Timeout fuer den Proxy-Call. Hoch, weil Agent-Loops (Pentests
|
|
# etc.) auch eine Stunde+ dauern koennen. Der Proxy seinerseits hat
|
|
# einen Idle-Watchdog (Default 20min Inaktivitaet) der den Subprocess
|
|
# killt, der dann seinen close-Event sendet — Brain bekommt also
|
|
# immer was zurueck, auch bei wirklich haengenden Subprozessen.
|
|
# Connect/Write/Pool sind klein (10/30/10s) damit toter Proxy
|
|
# schnell erkannt wird (siehe proxy_client.py).
|
|
- PROXY_TIMEOUT_SEC=${PROXY_TIMEOUT_SEC:-86400}
|
|
# OAuth-Callback-URL Bestandteile. Brain baut daraus
|
|
# https://{RVS_HOST}:{RVS_PORT_PUBLIC}/oauth/callback/{service} als
|
|
# redirect_uri fuer Provider wie Spotify/Google/etc. RVS_PORT_PUBLIC
|
|
# ist der nach aussen exposed Port (= TLS-Port hinter Caddy/Nginx),
|
|
# nicht der interne RVS-Container-Port.
|
|
- RVS_HOST=${RVS_HOST:-}
|
|
- RVS_PORT_PUBLIC=${RVS_PORT_PUBLIC:-${RVS_PORT:-443}}
|
|
- RVS_TLS=${RVS_TLS:-true}
|
|
volumes:
|
|
- ./aria-data/brain/data:/data # Memory-Cache + Skills + Models (bind-mount fuer Export)
|
|
- ./aria-data/brain-import:/import:ro # Quell-MDs fuer den initialen Memory-Import (read-only)
|
|
- ./aria-data/ssh:/root/.ssh # SSH-Keys fuer aria-wohnung (geteilt mit Proxy)
|
|
- aria-shared:/shared # gleicher Austausch-Speicher wie Bridge
|
|
restart: unless-stopped
|
|
networks:
|
|
- aria-net
|
|
|
|
# ─── ARIA Voice Bridge ──────────────────────────────────
|
|
bridge:
|
|
build: ./bridge
|
|
container_name: aria-bridge
|
|
depends_on:
|
|
- brain
|
|
networks:
|
|
- aria-net
|
|
ports:
|
|
- "3001:3001" # Diagnostic Web-UI (Diagnostic teilt Netzwerk mit Bridge)
|
|
volumes:
|
|
- aria-shared:/shared # Shared Volume fuer Datei-Austausch
|
|
# Audio-Zugriff
|
|
- /run/user/1000/pulse:/run/user/1000/pulse
|
|
- /dev/snd:/dev/snd
|
|
devices:
|
|
- /dev/snd
|
|
environment:
|
|
- PULSE_SERVER=unix:/run/user/1000/pulse/native
|
|
- BRAIN_URL=http://aria-brain:8080
|
|
- ARIA_AUTH_TOKEN=${ARIA_AUTH_TOKEN:-}
|
|
- RVS_HOST=${RVS_HOST:-}
|
|
- RVS_PORT=${RVS_PORT:-443}
|
|
- RVS_TLS=${RVS_TLS:-true}
|
|
- RVS_TLS_FALLBACK=${RVS_TLS_FALLBACK:-true}
|
|
- RVS_TOKEN=${RVS_TOKEN:-}
|
|
restart: unless-stopped
|
|
|
|
# ─── Diagnostic (Selbstcheck-UI und Einstellungen) ────
|
|
# Teilt Netzwerk mit Bridge, damit der Diagnostic-Server die
|
|
# Bridge auf localhost erreichen kann.
|
|
diagnostic:
|
|
build: ./diagnostic
|
|
container_name: aria-diagnostic
|
|
depends_on:
|
|
- bridge
|
|
network_mode: "service:bridge"
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock # Container Restart + Brain-Export/Import
|
|
- ./aria-data/config/diag-state:/data # Persistenter State (aktive Session etc.)
|
|
- aria-shared:/shared # Shared Volume (Uploads + Config + Voices)
|
|
- ./aria-data/brain:/brain # Brain-Export/Import (tar.gz aus Bind-Mount)
|
|
environment:
|
|
- ARIA_AUTH_TOKEN=${ARIA_AUTH_TOKEN:-}
|
|
- PROXY_URL=http://proxy:3456
|
|
- BRAIN_URL=http://aria-brain:8080
|
|
- RVS_HOST=${RVS_HOST:-}
|
|
- RVS_PORT=${RVS_PORT:-443}
|
|
- RVS_TLS=${RVS_TLS:-true}
|
|
- RVS_TLS_FALLBACK=${RVS_TLS_FALLBACK:-true}
|
|
- RVS_TOKEN=${RVS_TOKEN:-}
|
|
restart: unless-stopped
|
|
|
|
volumes:
|
|
aria-shared: # Datei-Austausch zwischen Bridge / Brain / Diagnostic
|
|
|
|
networks:
|
|
aria-net:
|
|
driver: bridge
|