diff --git a/.github/workflows/smoke-copilot-byok.lock.yml b/.github/workflows/smoke-copilot-byok.lock.yml index ed51cbc5..91f81998 100644 --- a/.github/workflows/smoke-copilot-byok.lock.yml +++ b/.github/workflows/smoke-copilot-byok.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"de7d4c7e7e258e37b0372086619480163a1e39f2639650ef7d3cbfe2471710fa","compiler_version":"v0.68.3","strict":true,"agent_id":"copilot"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"92f6aa4829de1e7ceadea14f9854fe57299c56bd360c084eee95650731f35fb3","compiler_version":"v0.68.3","strict":true,"agent_id":"copilot"} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"ba90f2186d7ad780ec640f364005fa24e797b360","version":"v0.68.3"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.20"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.25.20"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.20"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.19"},{"image":"ghcr.io/github/github-mcp-server:v0.32.0"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) @@ -26,6 +26,7 @@ # # Frontmatter env variables: # - COPILOT_API_KEY: (main workflow) +# - COPILOT_MODEL: (main workflow) # # Secrets used: # - COPILOT_GITHUB_TOKEN @@ -77,6 +78,7 @@ run-name: "Smoke Copilot BYOK" env: COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_MODEL: claude-opus-4.6 jobs: activation: @@ -192,6 +194,8 @@ jobs: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl GH_AW_EXPR_2805DAC9: ${{ steps.smoke-data.outputs.SMOKE_FILE_PATH }} + GH_AW_EXPR_7EA93000: ${{ steps.smoke-data.outputs.SMOKE_HTTP_CODE }} + GH_AW_EXPR_ABDF8D58: ${{ steps.smoke-data.outputs.SMOKE_PR_DATA }} GH_AW_EXPR_EC16C26C: ${{ steps.smoke-data.outputs.SMOKE_FILE_CONTENT }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} @@ -205,14 +209,14 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_2fb68bae1c8f1b53_EOF' + cat << 'GH_AW_PROMPT_c7171ddd49346715_EOF' - GH_AW_PROMPT_2fb68bae1c8f1b53_EOF + GH_AW_PROMPT_c7171ddd49346715_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_2fb68bae1c8f1b53_EOF' + cat << 'GH_AW_PROMPT_c7171ddd49346715_EOF' Tools: add_comment, add_labels, missing_tool, missing_data, noop @@ -244,12 +248,12 @@ jobs: {{/if}} - GH_AW_PROMPT_2fb68bae1c8f1b53_EOF + GH_AW_PROMPT_c7171ddd49346715_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/cli_proxy_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_2fb68bae1c8f1b53_EOF' + cat << 'GH_AW_PROMPT_c7171ddd49346715_EOF' {{#runtime-import .github/workflows/smoke-copilot-byok.md}} - GH_AW_PROMPT_2fb68bae1c8f1b53_EOF + GH_AW_PROMPT_c7171ddd49346715_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -258,6 +262,8 @@ jobs: GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_EXPR_EC16C26C: ${{ steps.smoke-data.outputs.SMOKE_FILE_CONTENT }} GH_AW_EXPR_2805DAC9: ${{ steps.smoke-data.outputs.SMOKE_FILE_PATH }} + GH_AW_EXPR_7EA93000: ${{ steps.smoke-data.outputs.SMOKE_HTTP_CODE }} + GH_AW_EXPR_ABDF8D58: ${{ steps.smoke-data.outputs.SMOKE_PR_DATA }} with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -269,6 +275,8 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_EXPR_2805DAC9: ${{ steps.smoke-data.outputs.SMOKE_FILE_PATH }} + GH_AW_EXPR_7EA93000: ${{ steps.smoke-data.outputs.SMOKE_HTTP_CODE }} + GH_AW_EXPR_ABDF8D58: ${{ steps.smoke-data.outputs.SMOKE_PR_DATA }} GH_AW_EXPR_EC16C26C: ${{ steps.smoke-data.outputs.SMOKE_FILE_CONTENT }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} @@ -290,6 +298,8 @@ jobs: file: process.env.GH_AW_PROMPT, substitutions: { GH_AW_EXPR_2805DAC9: process.env.GH_AW_EXPR_2805DAC9, + GH_AW_EXPR_7EA93000: process.env.GH_AW_EXPR_7EA93000, + GH_AW_EXPR_ABDF8D58: process.env.GH_AW_EXPR_ABDF8D58, GH_AW_EXPR_EC16C26C: process.env.GH_AW_EXPR_EC16C26C, GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, @@ -376,9 +386,11 @@ jobs: run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - id: smoke-data + - env: + GH_TOKEN: ${{ github.token }} + id: smoke-data name: Pre-compute BYOK smoke test data - run: "echo \"::group::Verify BYOK configuration\"\necho \"COPILOT_API_KEY=${COPILOT_API_KEY:+set (${#COPILOT_API_KEY} chars)}\"\necho \"COPILOT_API_TARGET=${COPILOT_API_TARGET:-api.githubcopilot.com (default)}\"\necho \"::endgroup::\"\n\necho \"::group::File write/read test\"\nTEST_DIR=\"/tmp/gh-aw/agent\"\nTEST_FILE=\"$TEST_DIR/smoke-test-copilot-byok-${GITHUB_RUN_ID}.txt\"\nmkdir -p \"$TEST_DIR\"\necho \"BYOK smoke test passed at $(date)\" > \"$TEST_FILE\"\nFILE_CONTENT=$(cat \"$TEST_FILE\")\necho \"Wrote and read back: $FILE_CONTENT\"\necho \"::endgroup::\"\n\n{\n echo \"SMOKE_FILE_CONTENT=$FILE_CONTENT\"\n echo \"SMOKE_FILE_PATH=$TEST_FILE\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: "echo \"::group::Verify BYOK configuration\"\necho \"COPILOT_API_KEY=${COPILOT_API_KEY:+set (${#COPILOT_API_KEY} chars)}\"\necho \"COPILOT_API_TARGET=${COPILOT_API_TARGET:-api.githubcopilot.com (default)}\"\necho \"::endgroup::\"\n\necho \"::group::Fetching last 2 merged PRs\"\nPR_DATA=$(gh pr list --repo \"$GITHUB_REPOSITORY\" --state merged --limit 2 \\\n --json number,title,author,mergedAt \\\n --jq '.[] | \"PR #\\(.number): \\(.title) (by @\\(.author.login), merged \\(.mergedAt))\"')\necho \"$PR_DATA\"\necho \"::endgroup::\"\n\necho \"::group::GitHub.com connectivity check\"\nHTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 https://github.com)\necho \"github.com returned HTTP $HTTP_CODE\"\necho \"::endgroup::\"\n\necho \"::group::File write/read test\"\nTEST_DIR=\"/tmp/gh-aw/agent\"\nTEST_FILE=\"$TEST_DIR/smoke-test-copilot-byok-${GITHUB_RUN_ID}.txt\"\nmkdir -p \"$TEST_DIR\"\necho \"BYOK smoke test passed at $(date)\" > \"$TEST_FILE\"\nFILE_CONTENT=$(cat \"$TEST_FILE\")\necho \"Wrote and read back: $FILE_CONTENT\"\necho \"::endgroup::\"\n\n{\n echo \"SMOKE_PR_DATA<> \"$GITHUB_OUTPUT\"\n" - name: Configure Git credentials env: @@ -408,7 +420,7 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.21 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.28 env: GH_HOST: github.com - name: Install awf dependencies @@ -453,9 +465,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_109df9f4f636e998_EOF' + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_949b89c0812a87fb_EOF' {"add_comment":{"hide_older_comments":true,"max":1},"add_labels":{"allowed":["smoke-copilot-byok"]},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_109df9f4f636e998_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_949b89c0812a87fb_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -656,7 +668,7 @@ jobs: export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.19' mkdir -p /home/runner/.copilot - cat << GH_AW_MCP_CONFIG_d97b07431cee7350_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh" + cat << GH_AW_MCP_CONFIG_249b3156ded81d6a_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh" { "mcpServers": { "safeoutputs": { @@ -681,7 +693,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_d97b07431cee7350_EOF + GH_AW_MCP_CONFIG_249b3156ded81d6a_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -712,7 +724,7 @@ jobs: env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-opus-4.6' }} GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt diff --git a/.github/workflows/smoke-copilot-byok.md b/.github/workflows/smoke-copilot-byok.md index 0d6eeee4..40319143 100644 --- a/.github/workflows/smoke-copilot-byok.md +++ b/.github/workflows/smoke-copilot-byok.md @@ -38,6 +38,7 @@ safe-outputs: timeout-minutes: 5 env: COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_MODEL: claude-opus-4.6 features: cli-proxy: true strict: true @@ -50,6 +51,18 @@ steps: echo "COPILOT_API_TARGET=${COPILOT_API_TARGET:-api.githubcopilot.com (default)}" echo "::endgroup::" + echo "::group::Fetching last 2 merged PRs" + PR_DATA=$(gh pr list --repo "$GITHUB_REPOSITORY" --state merged --limit 2 \ + --json number,title,author,mergedAt \ + --jq '.[] | "PR #\(.number): \(.title) (by @\(.author.login), merged \(.mergedAt))"') + echo "$PR_DATA" + echo "::endgroup::" + + echo "::group::GitHub.com connectivity check" + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 https://github.com) + echo "github.com returned HTTP $HTTP_CODE" + echo "::endgroup::" + echo "::group::File write/read test" TEST_DIR="/tmp/gh-aw/agent" TEST_FILE="$TEST_DIR/smoke-test-copilot-byok-${GITHUB_RUN_ID}.txt" @@ -60,9 +73,15 @@ steps: echo "::endgroup::" { + echo "SMOKE_PR_DATA<> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ github.token }} post-steps: - name: Validate safe outputs were invoked run: | @@ -105,21 +124,34 @@ This smoke test validates that Copilot CLI runs in **offline BYOK mode** — wit ## Pre-Computed Test Results -### 1. File Write/Read Test +The following tests were already executed in a deterministic pre-agent step. Your job is to verify the results and produce the summary comment. + +### 1. GitHub MCP Testing +Verify MCP connectivity by calling `github-list_pull_requests` for ${{ github.repository }} (limit 1, state merged). Confirm the result matches the pre-fetched data below. + +### 2. GitHub.com Connectivity +Pre-step result: HTTP ${{ steps.smoke-data.outputs.SMOKE_HTTP_CODE }} from github.com. +✅ if HTTP 200 or 301, ❌ otherwise. + +### 3. File Write/Read Test Pre-step wrote and read back: "${{ steps.smoke-data.outputs.SMOKE_FILE_CONTENT }}" File path: ${{ steps.smoke-data.outputs.SMOKE_FILE_PATH }} Verify by running `cat` on the file path using bash to confirm it exists. -### 2. GitHub MCP Testing -Verify MCP connectivity by calling `github-list_pull_requests` for ${{ github.repository }} (limit 1, state merged). Confirm the result returns data. - -### 3. BYOK Inference Test +### 4. BYOK Inference Test You are running in offline BYOK mode right now. The fact that you can read this prompt and respond means the BYOK inference path (agent → api-proxy sidecar → api.githubcopilot.com) is working. Confirm ✅. +## Pre-Fetched PR Data + +``` +${{ steps.smoke-data.outputs.SMOKE_PR_DATA }} +``` + ## Output Add a **very brief** comment (max 5-10 lines) to the current pull request with: -- ✅ or ❌ for each test result (file I/O, MCP, inference) +- PR titles only (no descriptions) +- ✅ or ❌ for each test result - Note: "Running in BYOK offline mode (COPILOT_OFFLINE=true) via api-proxy → api.githubcopilot.com" - Overall status: PASS or FAIL - Mention the pull request author and any assignees diff --git a/containers/api-proxy/server.js b/containers/api-proxy/server.js index 84889129..010ba5f1 100644 --- a/containers/api-proxy/server.js +++ b/containers/api-proxy/server.js @@ -78,6 +78,7 @@ function resolveCopilotAuthToken(env = process.env) { } const COPILOT_AUTH_TOKEN = resolveCopilotAuthToken(process.env); +const COPILOT_INTEGRATION_ID = process.env.COPILOT_INTEGRATION_ID || 'copilot-developer-cli'; const GEMINI_API_KEY = (process.env.GEMINI_API_KEY || '').trim() || undefined; /** @@ -337,7 +338,7 @@ function resolveOpenCodeRoute(openaiKey, anthropicKey, copilotToken, openaiTarge return { target: anthropicTarget, headers: { 'x-api-key': anthropicKey }, basePath: anthropicBasePath, needsAnthropicVersion: true }; } if (copilotToken) { - return { target: copilotTarget, headers: { 'Authorization': `Bearer ${copilotToken}` }, basePath: undefined, needsAnthropicVersion: false }; + return { target: copilotTarget, headers: { 'Authorization': `Bearer ${copilotToken}`, 'Copilot-Integration-Id': COPILOT_INTEGRATION_ID }, basePath: undefined, needsAnthropicVersion: false }; } return null; } @@ -1012,18 +1013,21 @@ if (require.main === module) { if (isModelsPath && req.method === 'GET' && COPILOT_GITHUB_TOKEN) { proxyRequest(req, res, COPILOT_API_TARGET, { 'Authorization': `Bearer ${COPILOT_GITHUB_TOKEN}`, + 'Copilot-Integration-Id': COPILOT_INTEGRATION_ID, }, 'copilot'); return; } proxyRequest(req, res, COPILOT_API_TARGET, { 'Authorization': `Bearer ${COPILOT_AUTH_TOKEN}`, + 'Copilot-Integration-Id': COPILOT_INTEGRATION_ID, }, 'copilot'); }); copilotServer.on('upgrade', (req, socket, head) => { proxyWebSocket(req, socket, head, COPILOT_API_TARGET, { 'Authorization': `Bearer ${COPILOT_AUTH_TOKEN}`, + 'Copilot-Integration-Id': COPILOT_INTEGRATION_ID, }, 'copilot'); });