Files
OmniRoute/scripts/devin-bridge/common
2026-07-29 10:02:02 -03:00

116 lines
4.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
BRIDGE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
BRIDGE_COMPOSE="$BRIDGE_ROOT/docker/devin-bridge/compose.yml"
BRIDGE_SANDBOX="$BRIDGE_ROOT/.sandbox"
bridge_prepare_sandbox() {
mkdir -p "$BRIDGE_SANDBOX/home" "$BRIDGE_SANDBOX/test-data" \
"$BRIDGE_SANDBOX/e2e-workspace" "$BRIDGE_SANDBOX/live-workspace" \
"$BRIDGE_SANDBOX/evidence"
chmod 0777 "$BRIDGE_SANDBOX/e2e-workspace" "$BRIDGE_SANDBOX/live-workspace" \
"$BRIDGE_SANDBOX/evidence"
}
bridge_reset_claude_egress_audit() {
bridge_prepare_sandbox
: >"$BRIDGE_SANDBOX/evidence/claude-egress.jsonl"
chmod 0666 "$BRIDGE_SANDBOX/evidence/claude-egress.jsonl"
}
bridge_reset_e2e_fixture() {
bridge_prepare_sandbox
cp -R "$BRIDGE_ROOT/tests/fixtures/devin-bridge/e2e-workspace/." \
"$BRIDGE_SANDBOX/e2e-workspace/"
rm -f "$BRIDGE_SANDBOX/e2e-workspace/.e2e-hook.log" \
"$BRIDGE_SANDBOX/evidence/claude-stream.jsonl" \
"$BRIDGE_SANDBOX/evidence/mock-acp.jsonl"
bridge_reset_claude_egress_audit
}
bridge_reset_live_fixture() {
bridge_prepare_sandbox
cp -R "$BRIDGE_ROOT/tests/fixtures/devin-bridge/e2e-workspace/." \
"$BRIDGE_SANDBOX/live-workspace/"
rm -f "$BRIDGE_SANDBOX/live-workspace/.e2e-hook.log" \
"$BRIDGE_SANDBOX/evidence/live-analysis.jsonl" \
"$BRIDGE_SANDBOX/evidence/live-fix.jsonl" \
"$BRIDGE_SANDBOX/evidence/live-command.jsonl" \
"$BRIDGE_SANDBOX/evidence/live-models.json" \
"$BRIDGE_SANDBOX/evidence/egress.jsonl"
bridge_reset_claude_egress_audit
}
bridge_test_env() {
bridge_prepare_sandbox
env HOME="$BRIDGE_SANDBOX/home" DATA_DIR="$BRIDGE_SANDBOX/test-data" SQLITE_FILE="$BRIDGE_SANDBOX/test-data/storage.sqlite" DEVIN_AGENTIC_HOME="$BRIDGE_SANDBOX/home" "$@"
}
bridge_run_devin() {
docker compose -f "$BRIDGE_COMPOSE" --profile live-devin run --rm --no-deps \
omniroute-live sh -ceu '
trusted_proxy=http://network-guard:8080
test "${DEVIN_BRIDGE_PROXY_URL:-}" = "$trusted_proxy"
export HTTP_PROXY="$trusted_proxy" HTTPS_PROXY="$trusted_proxy"
unset ALL_PROXY NO_PROXY http_proxy https_proxy all_proxy no_proxy
exec devin "$@"
' bridge-devin "$@"
}
bridge_assert_devin_auth_status() {
local exit_status="$1"
local output="$2"
[[ "$exit_status" == 0 ]] || {
printf 'FAIL: Devin auth status command failed\n' >&2
return 1
}
[[ "$output" == *"Logged in (via Devin)"* ]] || {
printf 'FAIL: Devin auth status did not confirm login\n' >&2
return 1
}
if grep -Fqi 'Failed to fetch from server' <<<"$output"; then
printf 'FAIL: Devin auth status could not confirm server access\n' >&2
return 1
fi
}
bridge_check_devin_auth() {
local output
local exit_status
set +e
output="$(bridge_run_devin auth status 2>&1)"
exit_status=$?
set -e
printf '%s\n' "$output"
bridge_assert_devin_auth_status "$exit_status" "$output"
}
bridge_assert_zero_claude_egress() {
local audit_path="$1"
[[ -f "$audit_path" ]] || {
printf 'FAIL: Claude egress audit file is missing\n' >&2
return 1
}
[[ ! -s "$audit_path" ]] || {
printf 'FAIL: Claude attempted external egress during the real run\n' >&2
return 1
}
}
bridge_assert_claude_guard_denials() {
local audit_path="$1"
[[ -s "$audit_path" ]] || {
printf 'FAIL: Claude egress denial audit is missing or empty\n' >&2
return 1
}
node -e '
const fs = require("node:fs");
const entries = fs.readFileSync(process.argv[1], "utf8")
.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
if (!entries.length) throw new Error("Claude egress audit has no records");
if (entries.some((entry) => entry.decision !== "deny")) {
throw new Error("Claude egress audit contains a non-deny decision");
}
for (const hostname of ["api.anthropic.com", "claude.ai"]) {
if (!entries.some((entry) => entry.hostname === hostname && entry.decision === "deny")) {
throw new Error(`Claude egress audit is missing deny for ${hostname}`);
}
}
' "$audit_path"
}