7822105058
security-review / approved (pull_request_review) Successful in 7s
qa-review / approved (pull_request_review) Successful in 10s
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 12s
E2E API Smoke Test / detect-changes (pull_request) Successful in 18s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 8s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 14s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 7s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 6s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 5s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 4s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 12s
sop-checklist / review-refire (pull_request_target) Has been skipped
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 15s
qa-review / approved (pull_request_target) Failing after 11s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
sop-checklist / na-declarations (pull_request) N/A: (none)
security-review / approved (pull_request_target) Failing after 11s
sop-checklist / all-items-acked (pull_request_target) Successful in 9s
gate-check-v3 / gate-check (pull_request_target) Successful in 23s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m1s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 5m6s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 2m39s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Successful in 2m59s
CI / Python Lint & Test (pull_request) Successful in 6s
CI / Detect changes (pull_request) Successful in 12s
CI / Platform (Go) (pull_request) Successful in 2s
CI / Canvas (Next.js) (pull_request) Successful in 2s
E2E Chat / detect-changes (pull_request) Successful in 7s
CI / Canvas Deploy Status (pull_request) Successful in 2s
E2E Chat / E2E Chat (pull_request) Successful in 8s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 21s
CI / all-required (pull_request) Successful in 4s
KI-013 removed 12-char UUID truncation from container/volume names. The E2E
scripts were still using ws-${ID:0:12} to inspect containers and volumes,
causing all local-provision E2E tests to fail (container not found).
Update all affected E2E scripts to use the full workspace ID:
- test_local_provision_lifecycle_e2e.sh
- test_claude_code_e2e.sh
- test_chat_attachments_e2e.sh
- test_chat_attachments_multiruntime_e2e.sh
- test_comprehensive_e2e.sh
Fixes SEV #2499.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
149 lines
6.5 KiB
Bash
Executable File
149 lines
6.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# Full E2E test for Claude Code workspace runtime
|
|
# Run from repo root after: docker compose up -d && docker build -t workspace:latest workspace/
|
|
#
|
|
# Prerequisites:
|
|
# - Platform running on localhost:8080
|
|
# - workspace:latest image built
|
|
# - .auth-token in workspace-configs-templates/claude-code-default/
|
|
|
|
set -euo pipefail
|
|
|
|
PLATFORM="http://localhost:8080"
|
|
export BASE="$PLATFORM"
|
|
source "$(dirname "$0")/_lib.sh"
|
|
PASS=0
|
|
FAIL=0
|
|
ERRORS=""
|
|
|
|
pass() { echo "PASS: $1"; PASS=$((PASS+1)); }
|
|
fail() { echo "FAIL: $1"; echo " expected: $2"; echo " got: $3"; FAIL=$((FAIL+1)); ERRORS="$ERRORS\n - $1"; }
|
|
|
|
check_contains() {
|
|
if echo "$3" | grep -qi "$2"; then pass "$1"; else fail "$1" "contains '$2'" "$3"; fi
|
|
}
|
|
|
|
# --- Health Check ---
|
|
echo "=== Claude Code E2E Tests ==="
|
|
echo ""
|
|
|
|
HEALTH=$(curl -s $PLATFORM/health)
|
|
check_contains "Platform healthy" '"status":"ok"' "$HEALTH"
|
|
|
|
# --- Verify auth token exists ---
|
|
if [ -f workspace-configs-templates/claude-code-default/.auth-token ]; then
|
|
pass "Auth token file exists"
|
|
else
|
|
fail "Auth token file exists" "file present" "missing"
|
|
echo "FATAL: No .auth-token. Write your Claude Code OAuth token to workspace-configs-templates/claude-code-default/.auth-token"
|
|
exit 1
|
|
fi
|
|
|
|
# --- Clean existing workspaces ---
|
|
e2e_cleanup_all_workspaces
|
|
# shellcheck disable=SC2046 # Intentional word-split over container IDs
|
|
docker stop $(docker ps -q --filter "name=ws-") 2>/dev/null || true
|
|
# shellcheck disable=SC2046
|
|
docker rm $(docker ps -aq --filter "name=ws-") 2>/dev/null || true
|
|
|
|
# --- Create Org Chart ---
|
|
echo ""
|
|
echo "--- Create Workspaces ---"
|
|
|
|
# model is required at the Create boundary (CTO 2026-05-22 SSOT —
|
|
# feedback_workspace_model_required_no_platform_default_dynamic_credential_intake).
|
|
# Pass the same value the deleted DefaultModel("claude-code") returned.
|
|
ROOT=$(curl -s -X POST $PLATFORM/workspaces -H "Content-Type: application/json" \
|
|
-d '{"name":"Root Agent","role":"Company coordinator","runtime":"claude-code","model":"sonnet","tier":3}' \
|
|
| python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
|
check_contains "Create root workspace" "-" "$ROOT"
|
|
|
|
CHILD=$(curl -s -X POST $PLATFORM/workspaces -H "Content-Type: application/json" \
|
|
-d "{\"name\":\"Child Agent\",\"role\":\"Sub-team member\",\"runtime\":\"claude-code\",\"model\":\"sonnet\",\"tier\":2,\"parent_id\":\"$ROOT\"}" \
|
|
| python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
|
check_contains "Create child workspace" "-" "$CHILD"
|
|
|
|
# --- Wait for online ---
|
|
echo ""
|
|
echo "--- Wait for provisioning (40s) ---"
|
|
sleep 40
|
|
|
|
ROOT_STATUS=$(curl -s "$PLATFORM/workspaces/$ROOT" | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
|
|
check_contains "Root is online" "online" "$ROOT_STATUS"
|
|
|
|
CHILD_STATUS=$(curl -s "$PLATFORM/workspaces/$CHILD" | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
|
|
check_contains "Child is online" "online" "$CHILD_STATUS"
|
|
|
|
# --- Containers running ---
|
|
CONTAINER_COUNT=$(docker ps --filter "name=ws-" -q | wc -l | tr -d ' ')
|
|
if [ "$CONTAINER_COUNT" -eq 2 ]; then pass "2 containers running"; else fail "2 containers running" "2" "$CONTAINER_COUNT"; fi
|
|
|
|
# --- Upload system prompts ---
|
|
echo ""
|
|
echo "--- Upload System Prompts ---"
|
|
|
|
ROOT_UPLOAD=$(curl -s -X PUT "$PLATFORM/workspaces/$ROOT/files" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"files":{"system-prompt.md":"You are the Root Agent. You coordinate sub-teams. The company is called TestCorp."}}')
|
|
check_contains "Upload root prompt" "replaced" "$ROOT_UPLOAD"
|
|
|
|
CHILD_UPLOAD=$(curl -s -X PUT "$PLATFORM/workspaces/$CHILD/files" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"files":{"system-prompt.md":"You are a Child Agent under Root. You specialize in data analysis for TestCorp."}}')
|
|
check_contains "Upload child prompt" "replaced" "$CHILD_UPLOAD"
|
|
|
|
# Verify prompts in containers
|
|
sleep 2
|
|
ROOT_CONTAINER=$(docker ps --filter "name=ws-${ROOT}" -q | head -1)
|
|
CHILD_CONTAINER=$(docker ps --filter "name=ws-${CHILD}" -q | head -1)
|
|
|
|
ROOT_HAS_PROMPT=$(docker exec $ROOT_CONTAINER cat /configs/system-prompt.md 2>/dev/null | head -1)
|
|
check_contains "Root container has prompt" "Root Agent" "$ROOT_HAS_PROMPT"
|
|
|
|
CHILD_HAS_PROMPT=$(docker exec $CHILD_CONTAINER cat /configs/system-prompt.md 2>/dev/null | head -1)
|
|
check_contains "Child container has prompt" "Child Agent" "$CHILD_HAS_PROMPT"
|
|
|
|
# --- A2A Tests ---
|
|
echo ""
|
|
echo "--- A2A Communication ---"
|
|
|
|
ROOT_REPLY=$(curl -s -X POST "$PLATFORM/workspaces/$ROOT/a2a" \
|
|
-H "Content-Type: application/json" --max-time 90 \
|
|
-d '{"jsonrpc":"2.0","id":"t1","method":"message/send","params":{"message":{"role":"user","parts":[{"type":"text","text":"What company do you work for? One word."}]}}}')
|
|
ROOT_TEXT=$(echo "$ROOT_REPLY" | python3 -c "import sys,json; d=json.load(sys.stdin); p=d.get('result',{}).get('parts',[]); print(p[0]['text'] if p else d.get('error',{}).get('message','EMPTY'))" 2>/dev/null)
|
|
check_contains "Root knows company name" "TestCorp" "$ROOT_TEXT"
|
|
|
|
CHILD_REPLY=$(curl -s -X POST "$PLATFORM/workspaces/$CHILD/a2a" \
|
|
-H "Content-Type: application/json" --max-time 90 \
|
|
-d '{"jsonrpc":"2.0","id":"t2","method":"message/send","params":{"message":{"role":"user","parts":[{"type":"text","text":"What do you specialize in? One phrase."}]}}}')
|
|
CHILD_TEXT=$(echo "$CHILD_REPLY" | python3 -c "import sys,json; d=json.load(sys.stdin); p=d.get('result',{}).get('parts',[]); print(p[0]['text'] if p else d.get('error',{}).get('message','EMPTY'))" 2>/dev/null)
|
|
check_contains "Child knows its specialty" "data" "$CHILD_TEXT"
|
|
|
|
# --- Access Control ---
|
|
echo ""
|
|
echo "--- Access Control ---"
|
|
|
|
PARENT_CHILD=$(curl -s -X POST $PLATFORM/registry/check-access -H "Content-Type: application/json" \
|
|
-d "{\"caller_id\":\"$ROOT\",\"target_id\":\"$CHILD\"}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('allowed','?'))")
|
|
check_contains "Parent→Child allowed" "True" "$PARENT_CHILD"
|
|
|
|
CHILD_PARENT=$(curl -s -X POST $PLATFORM/registry/check-access -H "Content-Type: application/json" \
|
|
-d "{\"caller_id\":\"$CHILD\",\"target_id\":\"$ROOT\"}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('allowed','?'))")
|
|
check_contains "Child→Parent allowed" "True" "$CHILD_PARENT"
|
|
|
|
# --- Canvas ---
|
|
echo ""
|
|
echo "--- Canvas ---"
|
|
CANVAS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000)
|
|
check_contains "Canvas returns 200" "200" "$CANVAS"
|
|
|
|
# --- Summary ---
|
|
echo ""
|
|
echo "==============================="
|
|
echo " PASS: $PASS FAIL: $FAIL"
|
|
echo "==============================="
|
|
if [ $FAIL -gt 0 ]; then
|
|
echo -e "\nFailed tests:$ERRORS"
|
|
exit 1
|
|
fi
|