From 528be11c95bcbe82212eab94b1deb8b99189d506 Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 19 Jun 2026 01:23:46 -0700 Subject: [PATCH 1/3] docs fixup --- docker-compose/executors/README.md | 14 +++++++------- .../executors/executor.docker-compose.yaml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docker-compose/executors/README.md b/docker-compose/executors/README.md index b0ae6d20d..a19b405a2 100644 --- a/docker-compose/executors/README.md +++ b/docker-compose/executors/README.md @@ -1,6 +1,6 @@ # Executors -Executors are Sourcegraph’s solution for running untrusted code in a secure and controllable way. For more information on executors and how they are used see the Executors [documentation](https://docs.sourcegraph.com/admin/executors) +Executors are Sourcegraph's solution for running untrusted code in a secure and controllable way. For more information on executors and how they are used see the Executors [documentation](https://sourcegraph.com/docs/self-hosted/executors). ## Deploying @@ -8,16 +8,16 @@ This directory contains a compose file to deploy a Sourcegraph Executor. NOTE: Executors require privileged access in order to run correctly on docker-compose based deployments. -To learn more visit TODO +To learn more visit the [Docker Compose executor deployment docs](https://sourcegraph.com/docs/self-hosted/executors/deploy-executors-docker). -To run this as part of a Sourcegraph deployment on the machine machine, execute the following command from the `docker-compose` directory: +To run this as part of a Sourcegraph deployment on the same machine, execute the following command from the `docker-compose` directory: ```bash -docker-compose -f docker-compose.yaml -f executors/executor.docker-compose.yaml up -d +docker compose -f docker-compose.yaml -f executors/executor.docker-compose.yaml up -d ``` -To run this on a standalone machine, execute the following from the `executors` directory +To run this on a standalone machine, execute the following from the `executors` directory: ```bash -docker-compose up -d executor.docker-compose.yaml -``` \ No newline at end of file +docker compose -f executor.docker-compose.yaml up -d +``` diff --git a/docker-compose/executors/executor.docker-compose.yaml b/docker-compose/executors/executor.docker-compose.yaml index c7fc82486..10b4296c8 100644 --- a/docker-compose/executors/executor.docker-compose.yaml +++ b/docker-compose/executors/executor.docker-compose.yaml @@ -10,7 +10,7 @@ services: # Run with privileged capabilities (required for docker daemon control) privileged: true environment: - # Refer to https://docs.sourcegraph.com/admin/executors/deploy_executors_binary#step-2-setup-environment-variables on how to populate these variables + # Refer to https://sourcegraph.com/docs/self-hosted/executors/executors-config on how to populate these variables - EXECUTOR_FRONTEND_URL=http://sourcegraph-frontend-0:3080 # Note: Must match `executors.accessToken` in site config - EXECUTOR_FRONTEND_PASSWORD= From 54c7c736c385c3963a05fe36f96a09c6148e1d9e Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 19 Jun 2026 01:43:08 -0700 Subject: [PATCH 2/3] add executors smoke test --- test/executor-smoke-test.sh | 111 ++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100755 test/executor-smoke-test.sh diff --git a/test/executor-smoke-test.sh b/test/executor-smoke-test.sh new file mode 100755 index 000000000..bb0996523 --- /dev/null +++ b/test/executor-smoke-test.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Executor smoke test for deploy-sourcegraph-docker +# +# Requires: a running Sourcegraph docker-compose stack (from smoke-test.sh or manual start). +# This script creates a site admin account, configures executor access, starts an executor +# container, and verifies it registers with the Sourcegraph instance. + +FRONTEND_URL="${FRONTEND_URL:-http://localhost:80}" +EXECUTOR_TOKEN="executor-smoke-test-token" +ADMIN_EMAIL="smoke-test@sourcegraph.com" +ADMIN_USERNAME="smoke-admin" +ADMIN_PASSWORD="smoke-test-password-123!" +COMPOSE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../docker-compose" && pwd)" +COOKIE_JAR=$(mktemp) +TOKEN_FILE=$(mktemp) + +cleanup() { + rm -f "$COOKIE_JAR" "$TOKEN_FILE" +} +trap cleanup EXIT + +echo "=== Executor Smoke Test ===" + +# Step 1: Create initial site admin account +echo "Step 1: Creating site admin account..." +INIT_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${FRONTEND_URL}/-/site-init" \ + -H 'Content-Type: application/json' \ + -d "{\"email\":\"${ADMIN_EMAIL}\",\"username\":\"${ADMIN_USERNAME}\",\"password\":\"${ADMIN_PASSWORD}\"}") +INIT_STATUS=$(echo "$INIT_RESPONSE" | tail -1) +if [ "$INIT_STATUS" = "200" ] || [ "$INIT_STATUS" = "201" ]; then + echo " Site admin created" +elif [ "$INIT_STATUS" = "409" ]; then + echo " Site admin already exists, continuing" +else + echo " Warning: site-init returned HTTP $INIT_STATUS, attempting to continue" +fi + +# Step 2: Sign in and get session cookie +echo "Step 2: Signing in..." +curl -s -c "$COOKIE_JAR" -X POST "${FRONTEND_URL}/-/sign-in" \ + -H 'Content-Type: application/json' \ + -d "{\"email\":\"${ADMIN_EMAIL}\",\"password\":\"${ADMIN_PASSWORD}\"}" + +# Step 3: Create access token +echo "Step 3: Creating access token..." +curl -s -b "$COOKIE_JAR" -X POST "${FRONTEND_URL}/.api/graphql" \ + -H 'Content-Type: application/json' \ + -d '{"query":"mutation { createAccessToken(user: \"VXNlcjox\", scopes: [\"user:all\"], note: \"executor-smoke-test\") { token } }"}' \ + | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['data']['createAccessToken']['token'])" > "$TOKEN_FILE" +echo " Access token created" + +# Step 4: Update site config with executor access token +echo "Step 4: Configuring executor access token in site config..." +TOKEN=$(cat "$TOKEN_FILE") +LAST_ID=$(curl -s -X POST "${FRONTEND_URL}/.api/graphql" \ + -H "Authorization: token $TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"query":"{ site { configuration { id } } }"}' \ + | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['data']['site']['configuration']['id'])") + +NEW_CONFIG=$(python3 -c "import json; print(json.dumps(json.dumps({'auth.providers': [{'type': 'builtin'}], 'executors.accessToken': '${EXECUTOR_TOKEN}'})))") + +curl -s -X POST "${FRONTEND_URL}/.api/graphql" \ + -H "Authorization: token $TOKEN" \ + -H 'Content-Type: application/json' \ + -d "{\"query\":\"mutation UpdateSiteConfig(\$input: String!) { updateSiteConfiguration(lastID: $LAST_ID, input: \$input) }\", \"variables\":{\"input\":$NEW_CONFIG}}" > /dev/null +echo " Site config updated" + +# Step 5: Start executor container +echo "Step 5: Starting executor container..." +EXECUTOR_CONTAINER=$(docker compose \ + -f "${COMPOSE_DIR}/docker-compose.yaml" \ + -f "${COMPOSE_DIR}/executors/executor.docker-compose.yaml" \ + run -d \ + -e "EXECUTOR_FRONTEND_PASSWORD=${EXECUTOR_TOKEN}" \ + -e EXECUTOR_QUEUE_NAME=batches \ + executor 2>&1 | tail -1) +echo " Executor container started: ${EXECUTOR_CONTAINER:0:12}" + +# Step 6: Wait for executor to register +echo "Step 6: Waiting for executor to register..." +MAX_ATTEMPTS=24 +for i in $(seq 1 $MAX_ATTEMPTS); do + COUNT=$(curl -s -X POST "${FRONTEND_URL}/.api/graphql" \ + -H "Authorization: token $TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"query":"{ executors(query: \"\", active: false) { totalCount } }"}' \ + | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['data']['executors']['totalCount'])" 2>/dev/null || echo "0") + + if [ "$COUNT" -ge 1 ]; then + echo " Executor registered after $((i * 5))s" + echo "" + echo "=== EXECUTOR SMOKE TEST PASSED ===" + exit 0 + fi + echo " Attempt $i/$MAX_ATTEMPTS - waiting 5s..." + sleep 5 +done + +echo "" +echo "=== EXECUTOR SMOKE TEST FAILED ===" +echo "Executor did not register within $((MAX_ATTEMPTS * 5))s" +echo "" +echo "Container status:" +docker inspect "$EXECUTOR_CONTAINER" --format '{{.State.Status}} (exit code: {{.State.ExitCode}})' 2>/dev/null || echo " Container not found" +echo "" +echo "Container logs:" +docker logs "$EXECUTOR_CONTAINER" 2>&1 | tail -20 || echo " No logs available" +exit 1 From 90d61b3913614e6156f35edf3a8506a1ad65bccb Mon Sep 17 00:00:00 2001 From: Warren Gifford Date: Fri, 19 Jun 2026 02:04:13 -0700 Subject: [PATCH 3/3] remove python for CI compatability Amp-Thread-ID: https://ampcode.com/threads/T-019ede70-71bd-726d-91b8-894438340faf Co-authored-by: Amp --- test/executor-smoke-test.sh | 48 +++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/test/executor-smoke-test.sh b/test/executor-smoke-test.sh index bb0996523..f92e1b474 100755 --- a/test/executor-smoke-test.sh +++ b/test/executor-smoke-test.sh @@ -6,6 +6,8 @@ set -euo pipefail # Requires: a running Sourcegraph docker-compose stack (from smoke-test.sh or manual start). # This script creates a site admin account, configures executor access, starts an executor # container, and verifies it registers with the Sourcegraph instance. +# +# Dependencies: curl, jq, docker compose FRONTEND_URL="${FRONTEND_URL:-http://localhost:80}" EXECUTOR_TOKEN="executor-smoke-test-token" @@ -13,22 +15,14 @@ ADMIN_EMAIL="smoke-test@sourcegraph.com" ADMIN_USERNAME="smoke-admin" ADMIN_PASSWORD="smoke-test-password-123!" COMPOSE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../docker-compose" && pwd)" -COOKIE_JAR=$(mktemp) -TOKEN_FILE=$(mktemp) - -cleanup() { - rm -f "$COOKIE_JAR" "$TOKEN_FILE" -} -trap cleanup EXIT echo "=== Executor Smoke Test ===" # Step 1: Create initial site admin account echo "Step 1: Creating site admin account..." -INIT_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${FRONTEND_URL}/-/site-init" \ +INIT_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${FRONTEND_URL}/-/site-init" \ -H 'Content-Type: application/json' \ -d "{\"email\":\"${ADMIN_EMAIL}\",\"username\":\"${ADMIN_USERNAME}\",\"password\":\"${ADMIN_PASSWORD}\"}") -INIT_STATUS=$(echo "$INIT_RESPONSE" | tail -1) if [ "$INIT_STATUS" = "200" ] || [ "$INIT_STATUS" = "201" ]; then echo " Site admin created" elif [ "$INIT_STATUS" = "409" ]; then @@ -37,35 +31,47 @@ else echo " Warning: site-init returned HTTP $INIT_STATUS, attempting to continue" fi -# Step 2: Sign in and get session cookie +# Step 2: Sign in and extract session cookie echo "Step 2: Signing in..." -curl -s -c "$COOKIE_JAR" -X POST "${FRONTEND_URL}/-/sign-in" \ +SESSION_COOKIE=$(curl -s -D - -o /dev/null -X POST "${FRONTEND_URL}/-/sign-in" \ -H 'Content-Type: application/json' \ - -d "{\"email\":\"${ADMIN_EMAIL}\",\"password\":\"${ADMIN_PASSWORD}\"}" + -d "{\"email\":\"${ADMIN_EMAIL}\",\"password\":\"${ADMIN_PASSWORD}\"}" \ + | tr -d '\r' | grep -i '^Set-Cookie: sgs=' | sed 's/^Set-Cookie: \([^;]*\).*/\1/') + +if [ -z "$SESSION_COOKIE" ]; then + echo " FAILED: Could not obtain session cookie" + exit 1 +fi +echo " Signed in" # Step 3: Create access token echo "Step 3: Creating access token..." -curl -s -b "$COOKIE_JAR" -X POST "${FRONTEND_URL}/.api/graphql" \ +TOKEN=$(curl -s --cookie "$SESSION_COOKIE" -X POST "${FRONTEND_URL}/.api/graphql" \ -H 'Content-Type: application/json' \ -d '{"query":"mutation { createAccessToken(user: \"VXNlcjox\", scopes: [\"user:all\"], note: \"executor-smoke-test\") { token } }"}' \ - | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['data']['createAccessToken']['token'])" > "$TOKEN_FILE" + | jq -r '.data.createAccessToken.token') + +if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then + echo " FAILED: Could not create access token" + exit 1 +fi echo " Access token created" # Step 4: Update site config with executor access token echo "Step 4: Configuring executor access token in site config..." -TOKEN=$(cat "$TOKEN_FILE") LAST_ID=$(curl -s -X POST "${FRONTEND_URL}/.api/graphql" \ -H "Authorization: token $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"query":"{ site { configuration { id } } }"}' \ - | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['data']['site']['configuration']['id'])") + | jq -r '.data.site.configuration.id') -NEW_CONFIG=$(python3 -c "import json; print(json.dumps(json.dumps({'auth.providers': [{'type': 'builtin'}], 'executors.accessToken': '${EXECUTOR_TOKEN}'})))") +NEW_CONFIG=$(jq -n --arg token "$EXECUTOR_TOKEN" \ + '{"auth.providers": [{"type": "builtin"}], "executors.accessToken": $token} | tojson') -curl -s -X POST "${FRONTEND_URL}/.api/graphql" \ +curl -s -o /dev/null -X POST "${FRONTEND_URL}/.api/graphql" \ -H "Authorization: token $TOKEN" \ -H 'Content-Type: application/json' \ - -d "{\"query\":\"mutation UpdateSiteConfig(\$input: String!) { updateSiteConfiguration(lastID: $LAST_ID, input: \$input) }\", \"variables\":{\"input\":$NEW_CONFIG}}" > /dev/null + --data-raw "{\"query\":\"mutation UpdateSiteConfig(\$input: String!) { updateSiteConfiguration(lastID: $LAST_ID, input: \$input) }\", \"variables\":{\"input\":$NEW_CONFIG}}" echo " Site config updated" # Step 5: Start executor container @@ -87,9 +93,9 @@ for i in $(seq 1 $MAX_ATTEMPTS); do -H "Authorization: token $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"query":"{ executors(query: \"\", active: false) { totalCount } }"}' \ - | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['data']['executors']['totalCount'])" 2>/dev/null || echo "0") + | jq -r '.data.executors.totalCount // 0') - if [ "$COUNT" -ge 1 ]; then + if [ "$COUNT" -ge 1 ] 2>/dev/null; then echo " Executor registered after $((i * 5))s" echo "" echo "=== EXECUTOR SMOKE TEST PASSED ==="