Merge pull request 'fix(e2e): surface tenant_call HTTP body on non-2xx (no more opaque curl:22)' (#2310) from fix/e2e-tenant-call-surface-body into main
ci-arm64-advisory / fast-checks (push) Waiting to run
Block internal-flavored paths / Block forbidden paths (push) Successful in 3s
CI / Detect changes (push) Successful in 5s
CI / Python Lint & Test (push) Successful in 5s
Handlers Postgres Integration / detect-changes (push) Successful in 4s
CI / Platform (Go) (push) Successful in 2s
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (push) Successful in 2s
CI / Canvas (Next.js) (push) Successful in 2s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 4s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 8s
CI / Canvas Deploy Status (push) Successful in 1s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 2s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (push) Successful in 13s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (push) Successful in 14s
E2E API Smoke Test / detect-changes (push) Successful in 15s
E2E Chat / detect-changes (push) Successful in 14s
CI / Shellcheck (E2E scripts) (push) Successful in 12s
E2E Chat / E2E Chat (push) Successful in 8s
CI / all-required (push) Successful in 1s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 54s
Handlers Postgres Integration / Handlers Postgres Integration (push) Successful in 2m21s
publish-workspace-server-image / build-and-push (push) Successful in 4m12s
E2E Staging SaaS (full lifecycle) / pr-validate (push) Compensated by status-reaper (push run was cancelled/superseded; Gitea 1.22.6 reports cancelled runs as failure statuses)
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (push) Compensated by status-reaper (push run was cancelled/superseded; Gitea 1.22.6 reports cancelled runs as failure statuses)
E2E Staging SaaS (full lifecycle) / E2E Staging Platform Boot (push) Compensated by status-reaper (push run was cancelled/superseded; Gitea 1.22.6 reports cancelled runs as failure statuses)
publish-workspace-server-image / Production auto-deploy (push) Successful in 2m46s
E2E Staging External Runtime / E2E Staging External Runtime (push) Successful in 5m33s

This commit was merged in pull request #2310.
This commit is contained in:
2026-06-05 16:59:17 +00:00
2 changed files with 32 additions and 3 deletions
+15 -3
View File
@@ -238,10 +238,17 @@ admin_call() {
# ─── 1. Create org ──────────────────────────────────────────────────────
log "1/8 Creating org $SLUG..."
# admin_call inherits CURL_COMMON's --fail-with-body: a non-2xx makes curl
# exit 22, which under `set -euo pipefail` would abort this bare command
# substitution BEFORE the `fail "... missing 'id'"` handler below can print
# the body. set +e / `|| true` keeps the 22 from tripping `set -e`; curl
# still wrote the body, so CREATE_RESP holds it and the id-check surfaces why.
set +e
CREATE_RESP=$(admin_call POST /cp/admin/orgs \
-d "{\"slug\":\"$SLUG\",\"name\":\"E2E ext $SLUG\",\"owner_user_id\":\"e2e-runner:$SLUG\"}")
ORG_ID=$(echo "$CREATE_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))")
[ -z "$ORG_ID" ] && fail "Org create response missing 'id'"
set -e
ORG_ID=$(echo "$CREATE_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || echo "")
[ -z "$ORG_ID" ] && fail "Org create response missing 'id': $(printf '%s' "$CREATE_RESP" | sanitize_http_body 2>/dev/null || printf '%s' "$CREATE_RESP")"
ok "Org created (id=$ORG_ID)"
# ─── 2. Wait for tenant provisioning ────────────────────────────────────
@@ -334,8 +341,13 @@ tenant_call() {
# on whatever the create handler set first (typically 'provisioning')
# because the follow-up UPDATE failed the enum cast.
log "4/8 Creating external workspace (no URL — exercises workspace.go:333)..."
# tenant_call inherits CURL_COMMON's --fail-with-body: guard the same way as
# the org create above so a non-2xx returns the body to the id/status checks
# below instead of aborting opaquely on curl exit 22.
set +e
WS_CREATE_RESP=$(tenant_call POST /workspaces \
-d '{"name":"ext-e2e","runtime":"external","external":true}')
set -e
WS_ID=$(echo "$WS_CREATE_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))")
WS_RESP_STATUS=$(echo "$WS_CREATE_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin).get('status',''))")
@@ -348,7 +360,7 @@ try:
except Exception:
print('')
")
[ -z "$WS_ID" ] && fail "Workspace create missing id: $WS_CREATE_RESP"
[ -z "$WS_ID" ] && fail "Workspace create missing id: $(printf '%s' "$WS_CREATE_RESP" | sanitize_http_body 2>/dev/null || printf '%s' "$WS_CREATE_RESP")"
[ "$WS_RESP_STATUS" != "awaiting_agent" ] && fail "Expected response status=awaiting_agent, got $WS_RESP_STATUS"
ok "Workspace created (id=$WS_ID, response status=awaiting_agent)"
+17
View File
@@ -710,9 +710,21 @@ if [ -n "$PROVISION_TEMPLATE" ]; then
else
log "5/11 Provisioning parent workspace (runtime=$RUNTIME)..."
fi
# tenant_call inherits CURL_COMMON's --fail-with-body, so a non-2xx create
# (e.g. the 422 RUNTIME_UNSUPPORTED below) makes curl exit 22. Capturing it
# bare as $(tenant_call ...) propagates that 22 through the command
# substitution and, under `set -euo pipefail`, ABORTS the whole script right
# here — before the `fail "... Response: ..."` handler below can print the
# body. The result was an opaque `curl: (22) ... error: 422` + teardown with
# no body (run 220702, main f78fef4c, step "5/11 Provisioning parent
# workspace"). set +e / `|| true` keeps the 22 from tripping `set -e`; curl
# still WROTE the body to stdout (that's what --fail-with-body does), so
# PARENT_RESP holds the 422 JSON and the id-check below surfaces WHY.
set +e
PARENT_RESP=$(tenant_call POST /workspaces \
-H "Content-Type: application/json" \
-d "$(build_create_payload 'E2E Parent')")
set -e
# Surface the workspace-create error CLEARLY instead of dying on a Python
# KeyError when the response has no 'id'. The load-bearing cases this names:
# - google-adk: RUNTIME_UNSUPPORTED 422 if google-adk is absent from the
@@ -733,9 +745,14 @@ log " PARENT_ID=$PARENT_ID"
CHILD_ID=""
if [ "$MODE" = "full" ]; then
log "6/11 Provisioning child workspace..."
# Same --fail-with-body / set -e abort guard as the parent create above:
# let a non-2xx return the body so the id-check below surfaces it instead
# of the script dying opaquely on curl exit 22.
set +e
CHILD_RESP=$(tenant_call POST /workspaces \
-H "Content-Type: application/json" \
-d "$(build_create_payload 'E2E Child' "$PARENT_ID")")
set -e
CHILD_ID=$(echo "$CHILD_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || echo "")
if [ -z "$CHILD_ID" ]; then
fail "Child workspace create returned no 'id' (runtime=$RUNTIME, template=${PROVISION_TEMPLATE:-<none>}). Response: $(printf '%s' "$CHILD_RESP" | sanitize_http_body)"