From 10dbc7ff15a1cee2873388249ae7c6bd347174a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 20:49:38 +0000 Subject: [PATCH 1/5] Initial plan From 63937542c87bd54ce1e50cf54a1ec31de0d680aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 20:56:30 +0000 Subject: [PATCH 2/5] Initial plan for docker network configuration for safeinputs MCP server Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/release.lock.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index a73e060474..160a26701e 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -6119,19 +6119,19 @@ jobs: - name: Download Go modules run: go mod download - name: Generate SBOM (SPDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 with: artifact-name: sbom.spdx.json format: spdx-json output-file: sbom.spdx.json - name: Generate SBOM (CycloneDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 with: artifact-name: sbom.cdx.json format: cyclonedx-json output-file: sbom.cdx.json - name: Upload SBOM artifacts - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: sbom-artifacts path: | From 49e76649d73edf5640a035b97c2e04e15de50638 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 21:07:45 +0000 Subject: [PATCH 3/5] Configure docker network for safeinputs MCP server - Add constants for docker network and container names - Create docker network setup step in agent job - Modify safeinputs to run in docker container on the network - Update URL configuration to use container name instead of localhost - Update tests to reflect docker container changes - Update TOML rendering for Codex engine Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../copilot-pr-merged-report.lock.yml | 82 +++++++----------- .../daily-performance-summary.lock.yml | 84 +++++++------------ .github/workflows/dev.lock.yml | 82 +++++++----------- .../smoke-copilot-playwright.lock.yml | 82 +++++++----------- .../smoke-copilot-safe-inputs.lock.yml | 82 +++++++----------- .../workflows/test-python-safe-input.lock.yml | 80 +++++++----------- pkg/constants/constants.go | 6 ++ pkg/workflow/mcp_renderer.go | 4 +- pkg/workflow/mcp_servers.go | 55 ++++++++++-- pkg/workflow/safe_inputs.go | 6 +- pkg/workflow/safe_inputs_http_codex_test.go | 6 +- .../safe_inputs_http_integration_test.go | 49 +++++++---- 12 files changed, 269 insertions(+), 349 deletions(-) diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml index 017c046a3d..6418202fe2 100644 --- a/.github/workflows/copilot-pr-merged-report.lock.yml +++ b/.github/workflows/copilot-pr-merged-report.lock.yml @@ -3152,76 +3152,52 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); + - name: Create Docker Network for Safe Inputs + run: | + docker network create gh-aw-network || true + echo 'Docker network created: gh-aw-network' + - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Set environment variables for the server - export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} - export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} - - export GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" + # Build docker run command + docker run -d --rm --init \ + --name safeinputs \ + --network gh-aw-network \ + -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ + -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ + -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ + -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ + -w /tmp/gh-aw/safe-inputs \ + node:24 \ + node mcp-server.cjs - cd /tmp/gh-aw/safe-inputs - # Verify required files exist - echo "Verifying safe-inputs setup..." - if [ ! -f mcp-server.cjs ]; then - echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - if [ ! -f tools.json ]; then - echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - echo "Configuration files verified" - # Log environment configuration - echo "Server configuration:" - echo " Port: $GH_AW_SAFE_INPUTS_PORT" - echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." - echo " Working directory: $(pwd)" - # Ensure logs directory exists - mkdir -p /tmp/gh-aw/safe-inputs/logs - # Create initial server.log file for artifact upload - echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log - echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log - # Start the HTTP server in the background - echo "Starting safe-inputs MCP HTTP server..." - node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & - SERVER_PID=$! - echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo "Waiting for server to become ready..." + echo 'Waiting for safe-inputs MCP server to be ready...' for i in {1..10}; do - # Check if process is still running - if ! kill -0 $SERVER_PID 2>/dev/null; then - echo "ERROR: Server process $SERVER_PID has died" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log + # Check if container is still running + if ! docker ps | grep -q safeinputs; then + echo "ERROR: Safe-inputs container has stopped" + docker logs safeinputs || true exit 1 fi - # Check if server is responding - if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then + + # Check if server is responding (using container name on the network) + if docker run --rm --network gh-aw-network curlimages/curl:latest \ + curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi + if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log - echo "Checking port availability:" - netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" + docker logs safeinputs || true exit 1 fi + echo "Waiting for server... (attempt $i/10)" sleep 1 done - # Output the configuration for the MCP client - echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT - echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: @@ -3237,7 +3213,7 @@ jobs: "mcpServers": { "safeinputs": { "type": "http", - "url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}", + "url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}", "headers": { "Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}" }, diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml index f6b7a8ce71..7ee2c65e60 100644 --- a/.github/workflows/daily-performance-summary.lock.yml +++ b/.github/workflows/daily-performance-summary.lock.yml @@ -4041,76 +4041,52 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); + - name: Create Docker Network for Safe Inputs + run: | + docker network create gh-aw-network || true + echo 'Docker network created: gh-aw-network' + - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Set environment variables for the server - export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} - export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} - - export GH_TOKEN="${GH_TOKEN}" - - cd /tmp/gh-aw/safe-inputs - # Verify required files exist - echo "Verifying safe-inputs setup..." - if [ ! -f mcp-server.cjs ]; then - echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - if [ ! -f tools.json ]; then - echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - echo "Configuration files verified" - # Log environment configuration - echo "Server configuration:" - echo " Port: $GH_AW_SAFE_INPUTS_PORT" - echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." - echo " Working directory: $(pwd)" - # Ensure logs directory exists - mkdir -p /tmp/gh-aw/safe-inputs/logs - # Create initial server.log file for artifact upload - echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log - echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log - # Start the HTTP server in the background - echo "Starting safe-inputs MCP HTTP server..." - node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & - SERVER_PID=$! - echo "Started safe-inputs MCP server with PID $SERVER_PID" + # Build docker run command + docker run -d --rm --init \ + --name safeinputs \ + --network gh-aw-network \ + -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ + -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ + -e GH_TOKEN="${GH_TOKEN}" \ + -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ + -w /tmp/gh-aw/safe-inputs \ + node:24 \ + node mcp-server.cjs + # Wait for server to be ready (max 10 seconds) - echo "Waiting for server to become ready..." + echo 'Waiting for safe-inputs MCP server to be ready...' for i in {1..10}; do - # Check if process is still running - if ! kill -0 $SERVER_PID 2>/dev/null; then - echo "ERROR: Server process $SERVER_PID has died" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log + # Check if container is still running + if ! docker ps | grep -q safeinputs; then + echo "ERROR: Safe-inputs container has stopped" + docker logs safeinputs || true exit 1 fi - # Check if server is responding - if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then + + # Check if server is responding (using container name on the network) + if docker run --rm --network gh-aw-network curlimages/curl:latest \ + curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi + if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log - echo "Checking port availability:" - netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" + docker logs safeinputs || true exit 1 fi + echo "Waiting for server... (attempt $i/10)" sleep 1 done - # Output the configuration for the MCP client - echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT - echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: @@ -4153,7 +4129,7 @@ jobs: [mcp_servers.safeinputs] type = "http" - url = "http://localhost:$GH_AW_SAFE_INPUTS_PORT" + url = "http://safeinputs:$GH_AW_SAFE_INPUTS_PORT" headers = { Authorization = "Bearer $GH_AW_SAFE_INPUTS_API_KEY" } env_vars = ["GH_AW_SAFE_INPUTS_PORT", "GH_AW_SAFE_INPUTS_API_KEY", "GH_TOKEN"] diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 32a106fa1e..835b14da6d 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -1737,76 +1737,52 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); + - name: Create Docker Network for Safe Inputs + run: | + docker network create gh-aw-network || true + echo 'Docker network created: gh-aw-network' + - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Set environment variables for the server - export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} - export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} - - export GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" + # Build docker run command + docker run -d --rm --init \ + --name safeinputs \ + --network gh-aw-network \ + -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ + -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ + -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ + -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ + -w /tmp/gh-aw/safe-inputs \ + node:24 \ + node mcp-server.cjs - cd /tmp/gh-aw/safe-inputs - # Verify required files exist - echo "Verifying safe-inputs setup..." - if [ ! -f mcp-server.cjs ]; then - echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - if [ ! -f tools.json ]; then - echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - echo "Configuration files verified" - # Log environment configuration - echo "Server configuration:" - echo " Port: $GH_AW_SAFE_INPUTS_PORT" - echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." - echo " Working directory: $(pwd)" - # Ensure logs directory exists - mkdir -p /tmp/gh-aw/safe-inputs/logs - # Create initial server.log file for artifact upload - echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log - echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log - # Start the HTTP server in the background - echo "Starting safe-inputs MCP HTTP server..." - node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & - SERVER_PID=$! - echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo "Waiting for server to become ready..." + echo 'Waiting for safe-inputs MCP server to be ready...' for i in {1..10}; do - # Check if process is still running - if ! kill -0 $SERVER_PID 2>/dev/null; then - echo "ERROR: Server process $SERVER_PID has died" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log + # Check if container is still running + if ! docker ps | grep -q safeinputs; then + echo "ERROR: Safe-inputs container has stopped" + docker logs safeinputs || true exit 1 fi - # Check if server is responding - if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then + + # Check if server is responding (using container name on the network) + if docker run --rm --network gh-aw-network curlimages/curl:latest \ + curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi + if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log - echo "Checking port availability:" - netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" + docker logs safeinputs || true exit 1 fi + echo "Waiting for server... (attempt $i/10)" sleep 1 done - # Output the configuration for the MCP client - echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT - echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: @@ -1820,7 +1796,7 @@ jobs: "mcpServers": { "safeinputs": { "type": "http", - "url": "http://localhost:$GH_AW_SAFE_INPUTS_PORT", + "url": "http://safeinputs:$GH_AW_SAFE_INPUTS_PORT", "headers": { "Authorization": "Bearer $GH_AW_SAFE_INPUTS_API_KEY" }, diff --git a/.github/workflows/smoke-copilot-playwright.lock.yml b/.github/workflows/smoke-copilot-playwright.lock.yml index f26a3d1841..ba4a7500c2 100644 --- a/.github/workflows/smoke-copilot-playwright.lock.yml +++ b/.github/workflows/smoke-copilot-playwright.lock.yml @@ -4655,76 +4655,52 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); + - name: Create Docker Network for Safe Inputs + run: | + docker network create gh-aw-network || true + echo 'Docker network created: gh-aw-network' + - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Set environment variables for the server - export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} - export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} - - export GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" + # Build docker run command + docker run -d --rm --init \ + --name safeinputs \ + --network gh-aw-network \ + -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ + -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ + -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ + -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ + -w /tmp/gh-aw/safe-inputs \ + node:24 \ + node mcp-server.cjs - cd /tmp/gh-aw/safe-inputs - # Verify required files exist - echo "Verifying safe-inputs setup..." - if [ ! -f mcp-server.cjs ]; then - echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - if [ ! -f tools.json ]; then - echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - echo "Configuration files verified" - # Log environment configuration - echo "Server configuration:" - echo " Port: $GH_AW_SAFE_INPUTS_PORT" - echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." - echo " Working directory: $(pwd)" - # Ensure logs directory exists - mkdir -p /tmp/gh-aw/safe-inputs/logs - # Create initial server.log file for artifact upload - echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log - echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log - # Start the HTTP server in the background - echo "Starting safe-inputs MCP HTTP server..." - node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & - SERVER_PID=$! - echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo "Waiting for server to become ready..." + echo 'Waiting for safe-inputs MCP server to be ready...' for i in {1..10}; do - # Check if process is still running - if ! kill -0 $SERVER_PID 2>/dev/null; then - echo "ERROR: Server process $SERVER_PID has died" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log + # Check if container is still running + if ! docker ps | grep -q safeinputs; then + echo "ERROR: Safe-inputs container has stopped" + docker logs safeinputs || true exit 1 fi - # Check if server is responding - if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then + + # Check if server is responding (using container name on the network) + if docker run --rm --network gh-aw-network curlimages/curl:latest \ + curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi + if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log - echo "Checking port availability:" - netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" + docker logs safeinputs || true exit 1 fi + echo "Waiting for server... (attempt $i/10)" sleep 1 done - # Output the configuration for the MCP client - echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT - echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: @@ -4767,7 +4743,7 @@ jobs: }, "safeinputs": { "type": "http", - "url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}", + "url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}", "headers": { "Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}" }, diff --git a/.github/workflows/smoke-copilot-safe-inputs.lock.yml b/.github/workflows/smoke-copilot-safe-inputs.lock.yml index dec1c7ae63..2840e64bfc 100644 --- a/.github/workflows/smoke-copilot-safe-inputs.lock.yml +++ b/.github/workflows/smoke-copilot-safe-inputs.lock.yml @@ -4555,76 +4555,52 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); + - name: Create Docker Network for Safe Inputs + run: | + docker network create gh-aw-network || true + echo 'Docker network created: gh-aw-network' + - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Set environment variables for the server - export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} - export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} - - export GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" + # Build docker run command + docker run -d --rm --init \ + --name safeinputs \ + --network gh-aw-network \ + -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ + -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ + -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ + -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ + -w /tmp/gh-aw/safe-inputs \ + node:24 \ + node mcp-server.cjs - cd /tmp/gh-aw/safe-inputs - # Verify required files exist - echo "Verifying safe-inputs setup..." - if [ ! -f mcp-server.cjs ]; then - echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - if [ ! -f tools.json ]; then - echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - echo "Configuration files verified" - # Log environment configuration - echo "Server configuration:" - echo " Port: $GH_AW_SAFE_INPUTS_PORT" - echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." - echo " Working directory: $(pwd)" - # Ensure logs directory exists - mkdir -p /tmp/gh-aw/safe-inputs/logs - # Create initial server.log file for artifact upload - echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log - echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log - # Start the HTTP server in the background - echo "Starting safe-inputs MCP HTTP server..." - node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & - SERVER_PID=$! - echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo "Waiting for server to become ready..." + echo 'Waiting for safe-inputs MCP server to be ready...' for i in {1..10}; do - # Check if process is still running - if ! kill -0 $SERVER_PID 2>/dev/null; then - echo "ERROR: Server process $SERVER_PID has died" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log + # Check if container is still running + if ! docker ps | grep -q safeinputs; then + echo "ERROR: Safe-inputs container has stopped" + docker logs safeinputs || true exit 1 fi - # Check if server is responding - if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then + + # Check if server is responding (using container name on the network) + if docker run --rm --network gh-aw-network curlimages/curl:latest \ + curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi + if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log - echo "Checking port availability:" - netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" + docker logs safeinputs || true exit 1 fi + echo "Waiting for server... (attempt $i/10)" sleep 1 done - # Output the configuration for the MCP client - echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT - echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: @@ -4640,7 +4616,7 @@ jobs: "mcpServers": { "safeinputs": { "type": "http", - "url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}", + "url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}", "headers": { "Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}" }, diff --git a/.github/workflows/test-python-safe-input.lock.yml b/.github/workflows/test-python-safe-input.lock.yml index dd13a92b0a..86c1b72686 100644 --- a/.github/workflows/test-python-safe-input.lock.yml +++ b/.github/workflows/test-python-safe-input.lock.yml @@ -3016,75 +3016,51 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); + - name: Create Docker Network for Safe Inputs + run: | + docker network create gh-aw-network || true + echo 'Docker network created: gh-aw-network' + - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Set environment variables for the server - export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} - export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} - + # Build docker run command + docker run -d --rm --init \ + --name safeinputs \ + --network gh-aw-network \ + -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ + -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ + -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ + -w /tmp/gh-aw/safe-inputs \ + node:24 \ + node mcp-server.cjs - cd /tmp/gh-aw/safe-inputs - # Verify required files exist - echo "Verifying safe-inputs setup..." - if [ ! -f mcp-server.cjs ]; then - echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - if [ ! -f tools.json ]; then - echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" - ls -la /tmp/gh-aw/safe-inputs/ - exit 1 - fi - echo "Configuration files verified" - # Log environment configuration - echo "Server configuration:" - echo " Port: $GH_AW_SAFE_INPUTS_PORT" - echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." - echo " Working directory: $(pwd)" - # Ensure logs directory exists - mkdir -p /tmp/gh-aw/safe-inputs/logs - # Create initial server.log file for artifact upload - echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log - echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log - echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log - # Start the HTTP server in the background - echo "Starting safe-inputs MCP HTTP server..." - node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & - SERVER_PID=$! - echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo "Waiting for server to become ready..." + echo 'Waiting for safe-inputs MCP server to be ready...' for i in {1..10}; do - # Check if process is still running - if ! kill -0 $SERVER_PID 2>/dev/null; then - echo "ERROR: Server process $SERVER_PID has died" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log + # Check if container is still running + if ! docker ps | grep -q safeinputs; then + echo "ERROR: Safe-inputs container has stopped" + docker logs safeinputs || true exit 1 fi - # Check if server is responding - if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then + + # Check if server is responding (using container name on the network) + if docker run --rm --network gh-aw-network curlimages/curl:latest \ + curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi + if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" - echo "Server log contents:" - cat /tmp/gh-aw/safe-inputs/logs/server.log - echo "Checking port availability:" - netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" + docker logs safeinputs || true exit 1 fi + echo "Waiting for server... (attempt $i/10)" sleep 1 done - # Output the configuration for the MCP client - echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT - echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: @@ -3120,7 +3096,7 @@ jobs: }, "safeinputs": { "type": "http", - "url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}", + "url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}", "headers": { "Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}" }, diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 8217a95908..4780434e33 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -221,6 +221,12 @@ const SafeInputsMCPServerID = "safeinputs" // SafeInputsMCPVersion is the version of the safe-inputs MCP server const SafeInputsMCPVersion = "1.0.0" +// SafeInputsDockerNetwork is the name of the Docker network for safe-inputs +const SafeInputsDockerNetwork = "gh-aw-network" + +// SafeInputsContainerName is the name of the safe-inputs Docker container +const SafeInputsContainerName = "safeinputs" + // Step IDs for pre-activation job const CheckMembershipStepID = "check_membership" const CheckStopTimeStepID = "check_stop_time" diff --git a/pkg/workflow/mcp_renderer.go b/pkg/workflow/mcp_renderer.go index f88ea71ba1..e414ca1794 100644 --- a/pkg/workflow/mcp_renderer.go +++ b/pkg/workflow/mcp_renderer.go @@ -219,14 +219,14 @@ func (r *MCPConfigRendererUnified) RenderSafeInputsMCP(yaml *strings.Builder, sa } // renderSafeInputsTOML generates Safe Inputs MCP configuration in TOML format -// Uses HTTP transport for consistency with JSON format (Copilot/Claude) +// Uses HTTP transport with container name for Docker network connectivity func (r *MCPConfigRendererUnified) renderSafeInputsTOML(yaml *strings.Builder, safeInputs *SafeInputsConfig) { envVars := getSafeInputsEnvVars(safeInputs) yaml.WriteString(" \n") yaml.WriteString(" [mcp_servers." + constants.SafeInputsMCPServerID + "]\n") yaml.WriteString(" type = \"http\"\n") - yaml.WriteString(" url = \"http://localhost:$GH_AW_SAFE_INPUTS_PORT\"\n") + yaml.WriteString(" url = \"http://" + constants.SafeInputsContainerName + ":$GH_AW_SAFE_INPUTS_PORT\"\n") yaml.WriteString(" headers = { Authorization = \"Bearer $GH_AW_SAFE_INPUTS_API_KEY\" }\n") // Add environment variables: server config + tool-specific vars diff --git a/pkg/workflow/mcp_servers.go b/pkg/workflow/mcp_servers.go index 58de9b0c66..69d224c301 100644 --- a/pkg/workflow/mcp_servers.go +++ b/pkg/workflow/mcp_servers.go @@ -438,24 +438,61 @@ func (c *Compiler) generateMCPSetup(yaml *strings.Builder, tools map[string]any, yaml.WriteString(" generateSafeInputsConfig({ core, crypto });\n") yaml.WriteString(" \n") - // Step 4: Start the HTTP server in the background + // Step 4: Create Docker network for safe-inputs + yaml.WriteString(" - name: Create Docker Network for Safe Inputs\n") + yaml.WriteString(" run: |\n") + yaml.WriteString(" docker network create " + constants.SafeInputsDockerNetwork + " || true\n") + yaml.WriteString(" echo 'Docker network created: " + constants.SafeInputsDockerNetwork + "'\n") + yaml.WriteString(" \n") + + // Step 5: Start the HTTP server in a Docker container yaml.WriteString(" - name: Start Safe Inputs MCP HTTP Server\n") yaml.WriteString(" id: safe-inputs-start\n") yaml.WriteString(" run: |\n") - yaml.WriteString(" # Set environment variables for the server\n") - yaml.WriteString(" export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }}\n") - yaml.WriteString(" export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }}\n") - yaml.WriteString(" \n") + yaml.WriteString(" # Build docker run command\n") + yaml.WriteString(" docker run -d --rm --init \\\n") + yaml.WriteString(" --name " + constants.SafeInputsContainerName + " \\\n") + yaml.WriteString(" --network " + constants.SafeInputsDockerNetwork + " \\\n") + yaml.WriteString(" -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \\\n") + yaml.WriteString(" -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \\\n") // Pass through environment variables from safe-inputs config envVars := getSafeInputsEnvVars(workflowData.SafeInputs) for _, envVar := range envVars { - yaml.WriteString(fmt.Sprintf(" export %s=\"${%s}\"\n", envVar, envVar)) + yaml.WriteString(fmt.Sprintf(" -e %s=\"${%s}\" \\\n", envVar, envVar)) } - yaml.WriteString(" \n") - // Use the embedded shell script to start the server - WriteShellScriptToYAML(yaml, startSafeInputsServerScript, " ") + yaml.WriteString(" -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \\\n") + yaml.WriteString(" -w /tmp/gh-aw/safe-inputs \\\n") + yaml.WriteString(" node:" + string(constants.DefaultNodeVersion) + " \\\n") + yaml.WriteString(" node mcp-server.cjs\n") + yaml.WriteString(" \n") + yaml.WriteString(" # Wait for server to be ready (max 10 seconds)\n") + yaml.WriteString(" echo 'Waiting for safe-inputs MCP server to be ready...'\n") + yaml.WriteString(" for i in {1..10}; do\n") + yaml.WriteString(" # Check if container is still running\n") + yaml.WriteString(" if ! docker ps | grep -q " + constants.SafeInputsContainerName + "; then\n") + yaml.WriteString(" echo \"ERROR: Safe-inputs container has stopped\"\n") + yaml.WriteString(" docker logs " + constants.SafeInputsContainerName + " || true\n") + yaml.WriteString(" exit 1\n") + yaml.WriteString(" fi\n") + yaml.WriteString(" \n") + yaml.WriteString(" # Check if server is responding (using container name on the network)\n") + yaml.WriteString(" if docker run --rm --network " + constants.SafeInputsDockerNetwork + " curlimages/curl:latest \\\n") + yaml.WriteString(" curl -s -f http://" + constants.SafeInputsContainerName + ":${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then\n") + yaml.WriteString(" echo \"Safe Inputs MCP server is ready (attempt $i/10)\"\n") + yaml.WriteString(" break\n") + yaml.WriteString(" fi\n") + yaml.WriteString(" \n") + yaml.WriteString(" if [ $i -eq 10 ]; then\n") + yaml.WriteString(" echo \"ERROR: Safe Inputs MCP server failed to start after 10 seconds\"\n") + yaml.WriteString(" docker logs " + constants.SafeInputsContainerName + " || true\n") + yaml.WriteString(" exit 1\n") + yaml.WriteString(" fi\n") + yaml.WriteString(" \n") + yaml.WriteString(" echo \"Waiting for server... (attempt $i/10)\"\n") + yaml.WriteString(" sleep 1\n") + yaml.WriteString(" done\n") yaml.WriteString(" \n") } diff --git a/pkg/workflow/safe_inputs.go b/pkg/workflow/safe_inputs.go index ed560af100..8dcc479efe 100644 --- a/pkg/workflow/safe_inputs.go +++ b/pkg/workflow/safe_inputs.go @@ -587,13 +587,13 @@ func renderSafeInputsMCPConfigWithOptions(yaml *strings.Builder, safeInputs *Saf // Add type field for HTTP (required by MCP specification for HTTP transport) yaml.WriteString(" \"type\": \"http\",\n") - // HTTP URL using environment variable + // HTTP URL using container name on docker network if includeCopilotFields { // Copilot format: backslash-escaped shell variable reference - yaml.WriteString(" \"url\": \"http://localhost:\\${GH_AW_SAFE_INPUTS_PORT}\",\n") + yaml.WriteString(" \"url\": \"http://" + constants.SafeInputsContainerName + ":\\${GH_AW_SAFE_INPUTS_PORT}\",\n") } else { // Claude/Custom format: direct shell variable reference - yaml.WriteString(" \"url\": \"http://localhost:$GH_AW_SAFE_INPUTS_PORT\",\n") + yaml.WriteString(" \"url\": \"http://" + constants.SafeInputsContainerName + ":$GH_AW_SAFE_INPUTS_PORT\",\n") } // Add Authorization header with API key diff --git a/pkg/workflow/safe_inputs_http_codex_test.go b/pkg/workflow/safe_inputs_http_codex_test.go index 7d890bbb75..4890c1c87c 100644 --- a/pkg/workflow/safe_inputs_http_codex_test.go +++ b/pkg/workflow/safe_inputs_http_codex_test.go @@ -72,9 +72,9 @@ Test safe-inputs HTTP transport for Codex t.Error("Expected type field set to 'http' in TOML format") } - // Should use HTTP transport (url + headers) - if !strings.Contains(yamlStr, `url = "http://localhost:$GH_AW_SAFE_INPUTS_PORT"`) { - t.Error("Expected HTTP URL config not found in TOML format") + // Should use HTTP transport (url + headers) with container name + if !strings.Contains(yamlStr, `url = "http://safeinputs:$GH_AW_SAFE_INPUTS_PORT"`) { + t.Error("Expected HTTP URL config with container name 'safeinputs' not found in TOML format") } if !strings.Contains(yamlStr, `headers = { Authorization = "Bearer $GH_AW_SAFE_INPUTS_API_KEY" }`) { diff --git a/pkg/workflow/safe_inputs_http_integration_test.go b/pkg/workflow/safe_inputs_http_integration_test.go index f7a9ff2595..b070503a85 100644 --- a/pkg/workflow/safe_inputs_http_integration_test.go +++ b/pkg/workflow/safe_inputs_http_integration_test.go @@ -54,6 +54,7 @@ Test safe-inputs HTTP server // Verify that the HTTP server configuration steps are generated expectedSteps := []string{ "Generate Safe Inputs MCP Server Config", + "Create Docker Network for Safe Inputs", "Start Safe Inputs MCP HTTP Server", "Setup MCPs", } @@ -64,6 +65,18 @@ Test safe-inputs HTTP server } } + // Verify docker network creation + dockerNetworkChecks := []string{ + "docker network create gh-aw-network", + "Docker network created: gh-aw-network", + } + + for _, check := range dockerNetworkChecks { + if !strings.Contains(yamlStr, check) { + t.Errorf("Expected docker network creation content not found: %q", check) + } + } + // Verify API key generation step uses github-script apiKeyGenChecks := []string{ "uses: actions/github-script@", @@ -77,12 +90,17 @@ Test safe-inputs HTTP server } } - // Verify HTTP server startup + // Verify Docker container startup serverStartupChecks := []string{ - "export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }}", - "export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }}", + "docker run -d --rm --init", + "--name safeinputs", + "--network gh-aw-network", + "-e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }}", + "-e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }}", + "-v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs", + "-w /tmp/gh-aw/safe-inputs", + "node:24", "node mcp-server.cjs", - "Started safe-inputs MCP server with PID", } for _, check := range serverStartupChecks { @@ -91,11 +109,13 @@ Test safe-inputs HTTP server } } - // Verify health check (health endpoint doesn't require auth) + // Verify health check using docker run with curl on the network healthCheckItems := []string{ - "curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health", + "docker run --rm --network gh-aw-network curlimages/curl:latest", + "curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health", "Safe Inputs MCP server is ready", "ERROR: Safe Inputs MCP server failed to start", + "docker logs safeinputs", } for _, check := range healthCheckItems { @@ -104,11 +124,11 @@ Test safe-inputs HTTP server } } - // Verify HTTP MCP configuration + // Verify HTTP MCP configuration uses container name expectedMCPChecks := []string{ `"safeinputs": {`, `"type": "http"`, - `"url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}"`, + `"url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}"`, `"headers": {`, `"Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}"`, `"tools": ["*"]`, @@ -183,10 +203,10 @@ Test safe-inputs with secrets yamlStr := string(lockContent) - // Verify that tool-specific env vars are passed to the HTTP server + // Verify that tool-specific env vars are passed to the Docker container serverEnvVarChecks := []string{ - `export API_KEY="${API_KEY}"`, - `export API_SECRET="${API_SECRET}"`, + `-e API_KEY="${API_KEY}"`, + `-e API_SECRET="${API_SECRET}"`, } for _, check := range serverEnvVarChecks { @@ -322,15 +342,16 @@ Test readiness check yamlStr := string(lockContent) - // Verify readiness check loop (health endpoint doesn't require auth) + // Verify readiness check loop using docker with container name on network readinessChecks := []string{ "for i in {1..10}; do", - "if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health", + "docker run --rm --network gh-aw-network curlimages/curl:latest", + "curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health", "Safe Inputs MCP server is ready", "break", "if [ $i -eq 10 ]; then", "ERROR: Safe Inputs MCP server failed to start after 10 seconds", - "cat /tmp/gh-aw/safe-inputs/logs/server.log", + "docker logs safeinputs", "exit 1", "sleep 1", } From ea2877b6d1476486a65991b1970a015ebf138dbb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 21:26:01 +0000 Subject: [PATCH 4/5] Fix docker network config with port mapping for safeinputs - Add port mapping to allow host access to container - Keep localhost URLs since agent accesses via mapped port - Container is accessible via container name from other containers on network - Remove unused startSafeInputsServerScript variable Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/copilot-pr-merged-report.lock.yml | 3 ++- .github/workflows/daily-performance-summary.lock.yml | 3 ++- .github/workflows/dev.lock.yml | 3 ++- .github/workflows/release.lock.yml | 6 +++--- .github/workflows/smoke-copilot-playwright.lock.yml | 3 ++- .github/workflows/smoke-copilot-safe-inputs.lock.yml | 3 ++- .github/workflows/test-python-safe-input.lock.yml | 3 ++- pkg/workflow/mcp_renderer.go | 4 ++-- pkg/workflow/mcp_servers.go | 1 + pkg/workflow/safe_inputs.go | 7 ++++--- pkg/workflow/safe_inputs_http_codex_test.go | 6 +++--- pkg/workflow/safe_inputs_http_integration_test.go | 7 ++++--- pkg/workflow/sh.go | 3 --- 13 files changed, 29 insertions(+), 23 deletions(-) diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml index 6418202fe2..2babf63da8 100644 --- a/.github/workflows/copilot-pr-merged-report.lock.yml +++ b/.github/workflows/copilot-pr-merged-report.lock.yml @@ -3164,6 +3164,7 @@ jobs: docker run -d --rm --init \ --name safeinputs \ --network gh-aw-network \ + -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ @@ -3213,7 +3214,7 @@ jobs: "mcpServers": { "safeinputs": { "type": "http", - "url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}", + "url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}", "headers": { "Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}" }, diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml index 7ee2c65e60..5961c2c035 100644 --- a/.github/workflows/daily-performance-summary.lock.yml +++ b/.github/workflows/daily-performance-summary.lock.yml @@ -4053,6 +4053,7 @@ jobs: docker run -d --rm --init \ --name safeinputs \ --network gh-aw-network \ + -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ -e GH_TOKEN="${GH_TOKEN}" \ @@ -4129,7 +4130,7 @@ jobs: [mcp_servers.safeinputs] type = "http" - url = "http://safeinputs:$GH_AW_SAFE_INPUTS_PORT" + url = "http://localhost:$GH_AW_SAFE_INPUTS_PORT" headers = { Authorization = "Bearer $GH_AW_SAFE_INPUTS_API_KEY" } env_vars = ["GH_AW_SAFE_INPUTS_PORT", "GH_AW_SAFE_INPUTS_API_KEY", "GH_TOKEN"] diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 835b14da6d..cb1647e8e6 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -1749,6 +1749,7 @@ jobs: docker run -d --rm --init \ --name safeinputs \ --network gh-aw-network \ + -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ @@ -1796,7 +1797,7 @@ jobs: "mcpServers": { "safeinputs": { "type": "http", - "url": "http://safeinputs:$GH_AW_SAFE_INPUTS_PORT", + "url": "http://localhost:$GH_AW_SAFE_INPUTS_PORT", "headers": { "Authorization": "Bearer $GH_AW_SAFE_INPUTS_API_KEY" }, diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 160a26701e..a73e060474 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -6119,19 +6119,19 @@ jobs: - name: Download Go modules run: go mod download - name: Generate SBOM (SPDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 with: artifact-name: sbom.spdx.json format: spdx-json output-file: sbom.spdx.json - name: Generate SBOM (CycloneDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 with: artifact-name: sbom.cdx.json format: cyclonedx-json output-file: sbom.cdx.json - name: Upload SBOM artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 with: name: sbom-artifacts path: | diff --git a/.github/workflows/smoke-copilot-playwright.lock.yml b/.github/workflows/smoke-copilot-playwright.lock.yml index ba4a7500c2..ac819943e3 100644 --- a/.github/workflows/smoke-copilot-playwright.lock.yml +++ b/.github/workflows/smoke-copilot-playwright.lock.yml @@ -4667,6 +4667,7 @@ jobs: docker run -d --rm --init \ --name safeinputs \ --network gh-aw-network \ + -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ @@ -4743,7 +4744,7 @@ jobs: }, "safeinputs": { "type": "http", - "url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}", + "url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}", "headers": { "Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}" }, diff --git a/.github/workflows/smoke-copilot-safe-inputs.lock.yml b/.github/workflows/smoke-copilot-safe-inputs.lock.yml index 2840e64bfc..de80d53392 100644 --- a/.github/workflows/smoke-copilot-safe-inputs.lock.yml +++ b/.github/workflows/smoke-copilot-safe-inputs.lock.yml @@ -4567,6 +4567,7 @@ jobs: docker run -d --rm --init \ --name safeinputs \ --network gh-aw-network \ + -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ @@ -4616,7 +4617,7 @@ jobs: "mcpServers": { "safeinputs": { "type": "http", - "url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}", + "url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}", "headers": { "Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}" }, diff --git a/.github/workflows/test-python-safe-input.lock.yml b/.github/workflows/test-python-safe-input.lock.yml index 86c1b72686..874f1cdf68 100644 --- a/.github/workflows/test-python-safe-input.lock.yml +++ b/.github/workflows/test-python-safe-input.lock.yml @@ -3028,6 +3028,7 @@ jobs: docker run -d --rm --init \ --name safeinputs \ --network gh-aw-network \ + -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ @@ -3096,7 +3097,7 @@ jobs: }, "safeinputs": { "type": "http", - "url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}", + "url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}", "headers": { "Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}" }, diff --git a/pkg/workflow/mcp_renderer.go b/pkg/workflow/mcp_renderer.go index e414ca1794..ed04a3cf5a 100644 --- a/pkg/workflow/mcp_renderer.go +++ b/pkg/workflow/mcp_renderer.go @@ -219,14 +219,14 @@ func (r *MCPConfigRendererUnified) RenderSafeInputsMCP(yaml *strings.Builder, sa } // renderSafeInputsTOML generates Safe Inputs MCP configuration in TOML format -// Uses HTTP transport with container name for Docker network connectivity +// Uses HTTP transport with localhost (container accessible via port mapping) func (r *MCPConfigRendererUnified) renderSafeInputsTOML(yaml *strings.Builder, safeInputs *SafeInputsConfig) { envVars := getSafeInputsEnvVars(safeInputs) yaml.WriteString(" \n") yaml.WriteString(" [mcp_servers." + constants.SafeInputsMCPServerID + "]\n") yaml.WriteString(" type = \"http\"\n") - yaml.WriteString(" url = \"http://" + constants.SafeInputsContainerName + ":$GH_AW_SAFE_INPUTS_PORT\"\n") + yaml.WriteString(" url = \"http://localhost:$GH_AW_SAFE_INPUTS_PORT\"\n") yaml.WriteString(" headers = { Authorization = \"Bearer $GH_AW_SAFE_INPUTS_API_KEY\" }\n") // Add environment variables: server config + tool-specific vars diff --git a/pkg/workflow/mcp_servers.go b/pkg/workflow/mcp_servers.go index 69d224c301..d0d52b2edc 100644 --- a/pkg/workflow/mcp_servers.go +++ b/pkg/workflow/mcp_servers.go @@ -453,6 +453,7 @@ func (c *Compiler) generateMCPSetup(yaml *strings.Builder, tools map[string]any, yaml.WriteString(" docker run -d --rm --init \\\n") yaml.WriteString(" --name " + constants.SafeInputsContainerName + " \\\n") yaml.WriteString(" --network " + constants.SafeInputsDockerNetwork + " \\\n") + yaml.WriteString(" -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \\\n") yaml.WriteString(" -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \\\n") yaml.WriteString(" -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \\\n") diff --git a/pkg/workflow/safe_inputs.go b/pkg/workflow/safe_inputs.go index 8dcc479efe..0faf76280c 100644 --- a/pkg/workflow/safe_inputs.go +++ b/pkg/workflow/safe_inputs.go @@ -587,13 +587,14 @@ func renderSafeInputsMCPConfigWithOptions(yaml *strings.Builder, safeInputs *Saf // Add type field for HTTP (required by MCP specification for HTTP transport) yaml.WriteString(" \"type\": \"http\",\n") - // HTTP URL using container name on docker network + // HTTP URL using localhost (port-mapped from container) + // Container is accessible via localhost from the host, and via container name from other containers on the network if includeCopilotFields { // Copilot format: backslash-escaped shell variable reference - yaml.WriteString(" \"url\": \"http://" + constants.SafeInputsContainerName + ":\\${GH_AW_SAFE_INPUTS_PORT}\",\n") + yaml.WriteString(" \"url\": \"http://localhost:\\${GH_AW_SAFE_INPUTS_PORT}\",\n") } else { // Claude/Custom format: direct shell variable reference - yaml.WriteString(" \"url\": \"http://" + constants.SafeInputsContainerName + ":$GH_AW_SAFE_INPUTS_PORT\",\n") + yaml.WriteString(" \"url\": \"http://localhost:$GH_AW_SAFE_INPUTS_PORT\",\n") } // Add Authorization header with API key diff --git a/pkg/workflow/safe_inputs_http_codex_test.go b/pkg/workflow/safe_inputs_http_codex_test.go index 4890c1c87c..7d890bbb75 100644 --- a/pkg/workflow/safe_inputs_http_codex_test.go +++ b/pkg/workflow/safe_inputs_http_codex_test.go @@ -72,9 +72,9 @@ Test safe-inputs HTTP transport for Codex t.Error("Expected type field set to 'http' in TOML format") } - // Should use HTTP transport (url + headers) with container name - if !strings.Contains(yamlStr, `url = "http://safeinputs:$GH_AW_SAFE_INPUTS_PORT"`) { - t.Error("Expected HTTP URL config with container name 'safeinputs' not found in TOML format") + // Should use HTTP transport (url + headers) + if !strings.Contains(yamlStr, `url = "http://localhost:$GH_AW_SAFE_INPUTS_PORT"`) { + t.Error("Expected HTTP URL config not found in TOML format") } if !strings.Contains(yamlStr, `headers = { Authorization = "Bearer $GH_AW_SAFE_INPUTS_API_KEY" }`) { diff --git a/pkg/workflow/safe_inputs_http_integration_test.go b/pkg/workflow/safe_inputs_http_integration_test.go index b070503a85..f08dee316b 100644 --- a/pkg/workflow/safe_inputs_http_integration_test.go +++ b/pkg/workflow/safe_inputs_http_integration_test.go @@ -90,11 +90,12 @@ Test safe-inputs HTTP server } } - // Verify Docker container startup + // Verify Docker container startup with port mapping serverStartupChecks := []string{ "docker run -d --rm --init", "--name safeinputs", "--network gh-aw-network", + "-p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}", "-e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }}", "-e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }}", "-v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs", @@ -124,11 +125,11 @@ Test safe-inputs HTTP server } } - // Verify HTTP MCP configuration uses container name + // Verify HTTP MCP configuration expectedMCPChecks := []string{ `"safeinputs": {`, `"type": "http"`, - `"url": "http://safeinputs:\${GH_AW_SAFE_INPUTS_PORT}"`, + `"url": "http://localhost:\${GH_AW_SAFE_INPUTS_PORT}"`, `"headers": {`, `"Authorization": "Bearer \${GH_AW_SAFE_INPUTS_API_KEY}"`, `"tools": ["*"]`, diff --git a/pkg/workflow/sh.go b/pkg/workflow/sh.go index 439cf0a76a..fcf0b3f4e5 100644 --- a/pkg/workflow/sh.go +++ b/pkg/workflow/sh.go @@ -24,9 +24,6 @@ var createCacheMemoryDirScript string //go:embed sh/create_gh_aw_tmp_dir.sh var createGhAwTmpDirScript string -//go:embed sh/start_safe_inputs_server.sh -var startSafeInputsServerScript string - //go:embed prompts/xpia_prompt.md var xpiaPromptText string From fdc57548ef8a365cc42bb9040215319847cc0672 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 21:36:24 +0000 Subject: [PATCH 5/5] Revert to running safe-inputs as host process (not container) Reverted Docker container implementation per feedback. Safe-inputs now runs as a regular Node.js process on the host, making it reachable from the AWF firewall process without Docker network complexity. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../copilot-pr-merged-report.lock.yml | 81 +++++++++++------- .../daily-performance-summary.lock.yml | 83 ++++++++++++------- .github/workflows/dev.lock.yml | 81 +++++++++++------- .github/workflows/release.lock.yml | 6 +- .../smoke-copilot-playwright.lock.yml | 81 +++++++++++------- .../smoke-copilot-safe-inputs.lock.yml | 81 +++++++++++------- .../workflows/test-python-safe-input.lock.yml | 79 +++++++++++------- pkg/constants/constants.go | 6 -- pkg/workflow/mcp_renderer.go | 2 +- pkg/workflow/mcp_servers.go | 56 ++----------- pkg/workflow/safe_inputs.go | 3 +- .../safe_inputs_http_integration_test.go | 46 +++------- pkg/workflow/sh.go | 3 + 13 files changed, 341 insertions(+), 267 deletions(-) diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml index 2babf63da8..017c046a3d 100644 --- a/.github/workflows/copilot-pr-merged-report.lock.yml +++ b/.github/workflows/copilot-pr-merged-report.lock.yml @@ -3152,53 +3152,76 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); - - name: Create Docker Network for Safe Inputs - run: | - docker network create gh-aw-network || true - echo 'Docker network created: gh-aw-network' - - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Build docker run command - docker run -d --rm --init \ - --name safeinputs \ - --network gh-aw-network \ - -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ - -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ - -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ - -w /tmp/gh-aw/safe-inputs \ - node:24 \ - node mcp-server.cjs + # Set environment variables for the server + export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} + export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} + + export GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" + cd /tmp/gh-aw/safe-inputs + # Verify required files exist + echo "Verifying safe-inputs setup..." + if [ ! -f mcp-server.cjs ]; then + echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + if [ ! -f tools.json ]; then + echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + echo "Configuration files verified" + # Log environment configuration + echo "Server configuration:" + echo " Port: $GH_AW_SAFE_INPUTS_PORT" + echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." + echo " Working directory: $(pwd)" + # Ensure logs directory exists + mkdir -p /tmp/gh-aw/safe-inputs/logs + # Create initial server.log file for artifact upload + echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log + echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log + # Start the HTTP server in the background + echo "Starting safe-inputs MCP HTTP server..." + node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & + SERVER_PID=$! + echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo 'Waiting for safe-inputs MCP server to be ready...' + echo "Waiting for server to become ready..." for i in {1..10}; do - # Check if container is still running - if ! docker ps | grep -q safeinputs; then - echo "ERROR: Safe-inputs container has stopped" - docker logs safeinputs || true + # Check if process is still running + if ! kill -0 $SERVER_PID 2>/dev/null; then + echo "ERROR: Server process $SERVER_PID has died" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log exit 1 fi - - # Check if server is responding (using container name on the network) - if docker run --rm --network gh-aw-network curlimages/curl:latest \ - curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then + # Check if server is responding + if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi - if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - docker logs safeinputs || true + echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log + echo "Checking port availability:" + netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" exit 1 fi - echo "Waiting for server... (attempt $i/10)" sleep 1 done + # Output the configuration for the MCP client + echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT + echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml index 5961c2c035..f6b7a8ce71 100644 --- a/.github/workflows/daily-performance-summary.lock.yml +++ b/.github/workflows/daily-performance-summary.lock.yml @@ -4041,53 +4041,76 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); - - name: Create Docker Network for Safe Inputs - run: | - docker network create gh-aw-network || true - echo 'Docker network created: gh-aw-network' - - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Build docker run command - docker run -d --rm --init \ - --name safeinputs \ - --network gh-aw-network \ - -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ - -e GH_TOKEN="${GH_TOKEN}" \ - -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ - -w /tmp/gh-aw/safe-inputs \ - node:24 \ - node mcp-server.cjs - + # Set environment variables for the server + export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} + export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} + + export GH_TOKEN="${GH_TOKEN}" + + cd /tmp/gh-aw/safe-inputs + # Verify required files exist + echo "Verifying safe-inputs setup..." + if [ ! -f mcp-server.cjs ]; then + echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + if [ ! -f tools.json ]; then + echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + echo "Configuration files verified" + # Log environment configuration + echo "Server configuration:" + echo " Port: $GH_AW_SAFE_INPUTS_PORT" + echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." + echo " Working directory: $(pwd)" + # Ensure logs directory exists + mkdir -p /tmp/gh-aw/safe-inputs/logs + # Create initial server.log file for artifact upload + echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log + echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log + # Start the HTTP server in the background + echo "Starting safe-inputs MCP HTTP server..." + node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & + SERVER_PID=$! + echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo 'Waiting for safe-inputs MCP server to be ready...' + echo "Waiting for server to become ready..." for i in {1..10}; do - # Check if container is still running - if ! docker ps | grep -q safeinputs; then - echo "ERROR: Safe-inputs container has stopped" - docker logs safeinputs || true + # Check if process is still running + if ! kill -0 $SERVER_PID 2>/dev/null; then + echo "ERROR: Server process $SERVER_PID has died" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log exit 1 fi - - # Check if server is responding (using container name on the network) - if docker run --rm --network gh-aw-network curlimages/curl:latest \ - curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then + # Check if server is responding + if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi - if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - docker logs safeinputs || true + echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log + echo "Checking port availability:" + netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" exit 1 fi - echo "Waiting for server... (attempt $i/10)" sleep 1 done + # Output the configuration for the MCP client + echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT + echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index cb1647e8e6..32a106fa1e 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -1737,53 +1737,76 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); - - name: Create Docker Network for Safe Inputs - run: | - docker network create gh-aw-network || true - echo 'Docker network created: gh-aw-network' - - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Build docker run command - docker run -d --rm --init \ - --name safeinputs \ - --network gh-aw-network \ - -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ - -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ - -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ - -w /tmp/gh-aw/safe-inputs \ - node:24 \ - node mcp-server.cjs + # Set environment variables for the server + export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} + export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} + + export GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" + cd /tmp/gh-aw/safe-inputs + # Verify required files exist + echo "Verifying safe-inputs setup..." + if [ ! -f mcp-server.cjs ]; then + echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + if [ ! -f tools.json ]; then + echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + echo "Configuration files verified" + # Log environment configuration + echo "Server configuration:" + echo " Port: $GH_AW_SAFE_INPUTS_PORT" + echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." + echo " Working directory: $(pwd)" + # Ensure logs directory exists + mkdir -p /tmp/gh-aw/safe-inputs/logs + # Create initial server.log file for artifact upload + echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log + echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log + # Start the HTTP server in the background + echo "Starting safe-inputs MCP HTTP server..." + node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & + SERVER_PID=$! + echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo 'Waiting for safe-inputs MCP server to be ready...' + echo "Waiting for server to become ready..." for i in {1..10}; do - # Check if container is still running - if ! docker ps | grep -q safeinputs; then - echo "ERROR: Safe-inputs container has stopped" - docker logs safeinputs || true + # Check if process is still running + if ! kill -0 $SERVER_PID 2>/dev/null; then + echo "ERROR: Server process $SERVER_PID has died" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log exit 1 fi - - # Check if server is responding (using container name on the network) - if docker run --rm --network gh-aw-network curlimages/curl:latest \ - curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then + # Check if server is responding + if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi - if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - docker logs safeinputs || true + echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log + echo "Checking port availability:" + netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" exit 1 fi - echo "Waiting for server... (attempt $i/10)" sleep 1 done + # Output the configuration for the MCP client + echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT + echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index a73e060474..160a26701e 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -6119,19 +6119,19 @@ jobs: - name: Download Go modules run: go mod download - name: Generate SBOM (SPDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 with: artifact-name: sbom.spdx.json format: spdx-json output-file: sbom.spdx.json - name: Generate SBOM (CycloneDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 with: artifact-name: sbom.cdx.json format: cyclonedx-json output-file: sbom.cdx.json - name: Upload SBOM artifacts - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: sbom-artifacts path: | diff --git a/.github/workflows/smoke-copilot-playwright.lock.yml b/.github/workflows/smoke-copilot-playwright.lock.yml index ac819943e3..f26a3d1841 100644 --- a/.github/workflows/smoke-copilot-playwright.lock.yml +++ b/.github/workflows/smoke-copilot-playwright.lock.yml @@ -4655,53 +4655,76 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); - - name: Create Docker Network for Safe Inputs - run: | - docker network create gh-aw-network || true - echo 'Docker network created: gh-aw-network' - - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Build docker run command - docker run -d --rm --init \ - --name safeinputs \ - --network gh-aw-network \ - -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ - -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ - -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ - -w /tmp/gh-aw/safe-inputs \ - node:24 \ - node mcp-server.cjs + # Set environment variables for the server + export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} + export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} + + export GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" + cd /tmp/gh-aw/safe-inputs + # Verify required files exist + echo "Verifying safe-inputs setup..." + if [ ! -f mcp-server.cjs ]; then + echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + if [ ! -f tools.json ]; then + echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + echo "Configuration files verified" + # Log environment configuration + echo "Server configuration:" + echo " Port: $GH_AW_SAFE_INPUTS_PORT" + echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." + echo " Working directory: $(pwd)" + # Ensure logs directory exists + mkdir -p /tmp/gh-aw/safe-inputs/logs + # Create initial server.log file for artifact upload + echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log + echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log + # Start the HTTP server in the background + echo "Starting safe-inputs MCP HTTP server..." + node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & + SERVER_PID=$! + echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo 'Waiting for safe-inputs MCP server to be ready...' + echo "Waiting for server to become ready..." for i in {1..10}; do - # Check if container is still running - if ! docker ps | grep -q safeinputs; then - echo "ERROR: Safe-inputs container has stopped" - docker logs safeinputs || true + # Check if process is still running + if ! kill -0 $SERVER_PID 2>/dev/null; then + echo "ERROR: Server process $SERVER_PID has died" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log exit 1 fi - - # Check if server is responding (using container name on the network) - if docker run --rm --network gh-aw-network curlimages/curl:latest \ - curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then + # Check if server is responding + if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi - if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - docker logs safeinputs || true + echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log + echo "Checking port availability:" + netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" exit 1 fi - echo "Waiting for server... (attempt $i/10)" sleep 1 done + # Output the configuration for the MCP client + echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT + echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: diff --git a/.github/workflows/smoke-copilot-safe-inputs.lock.yml b/.github/workflows/smoke-copilot-safe-inputs.lock.yml index de80d53392..dec1c7ae63 100644 --- a/.github/workflows/smoke-copilot-safe-inputs.lock.yml +++ b/.github/workflows/smoke-copilot-safe-inputs.lock.yml @@ -4555,53 +4555,76 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); - - name: Create Docker Network for Safe Inputs - run: | - docker network create gh-aw-network || true - echo 'Docker network created: gh-aw-network' - - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Build docker run command - docker run -d --rm --init \ - --name safeinputs \ - --network gh-aw-network \ - -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ - -e GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" \ - -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ - -w /tmp/gh-aw/safe-inputs \ - node:24 \ - node mcp-server.cjs + # Set environment variables for the server + export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} + export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} + + export GH_AW_GH_TOKEN="${GH_AW_GH_TOKEN}" + cd /tmp/gh-aw/safe-inputs + # Verify required files exist + echo "Verifying safe-inputs setup..." + if [ ! -f mcp-server.cjs ]; then + echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + if [ ! -f tools.json ]; then + echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + echo "Configuration files verified" + # Log environment configuration + echo "Server configuration:" + echo " Port: $GH_AW_SAFE_INPUTS_PORT" + echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." + echo " Working directory: $(pwd)" + # Ensure logs directory exists + mkdir -p /tmp/gh-aw/safe-inputs/logs + # Create initial server.log file for artifact upload + echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log + echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log + # Start the HTTP server in the background + echo "Starting safe-inputs MCP HTTP server..." + node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & + SERVER_PID=$! + echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo 'Waiting for safe-inputs MCP server to be ready...' + echo "Waiting for server to become ready..." for i in {1..10}; do - # Check if container is still running - if ! docker ps | grep -q safeinputs; then - echo "ERROR: Safe-inputs container has stopped" - docker logs safeinputs || true + # Check if process is still running + if ! kill -0 $SERVER_PID 2>/dev/null; then + echo "ERROR: Server process $SERVER_PID has died" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log exit 1 fi - - # Check if server is responding (using container name on the network) - if docker run --rm --network gh-aw-network curlimages/curl:latest \ - curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then + # Check if server is responding + if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi - if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - docker logs safeinputs || true + echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log + echo "Checking port availability:" + netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" exit 1 fi - echo "Waiting for server... (attempt $i/10)" sleep 1 done + # Output the configuration for the MCP client + echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT + echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: diff --git a/.github/workflows/test-python-safe-input.lock.yml b/.github/workflows/test-python-safe-input.lock.yml index 874f1cdf68..dd13a92b0a 100644 --- a/.github/workflows/test-python-safe-input.lock.yml +++ b/.github/workflows/test-python-safe-input.lock.yml @@ -3016,52 +3016,75 @@ jobs: const crypto = require('crypto'); generateSafeInputsConfig({ core, crypto }); - - name: Create Docker Network for Safe Inputs - run: | - docker network create gh-aw-network || true - echo 'Docker network created: gh-aw-network' - - name: Start Safe Inputs MCP HTTP Server id: safe-inputs-start run: | - # Build docker run command - docker run -d --rm --init \ - --name safeinputs \ - --network gh-aw-network \ - -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \ - -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \ - -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \ - -w /tmp/gh-aw/safe-inputs \ - node:24 \ - node mcp-server.cjs + # Set environment variables for the server + export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} + export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} + + cd /tmp/gh-aw/safe-inputs + # Verify required files exist + echo "Verifying safe-inputs setup..." + if [ ! -f mcp-server.cjs ]; then + echo "ERROR: mcp-server.cjs not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + if [ ! -f tools.json ]; then + echo "ERROR: tools.json not found in /tmp/gh-aw/safe-inputs" + ls -la /tmp/gh-aw/safe-inputs/ + exit 1 + fi + echo "Configuration files verified" + # Log environment configuration + echo "Server configuration:" + echo " Port: $GH_AW_SAFE_INPUTS_PORT" + echo " API Key: ${GH_AW_SAFE_INPUTS_API_KEY:0:8}..." + echo " Working directory: $(pwd)" + # Ensure logs directory exists + mkdir -p /tmp/gh-aw/safe-inputs/logs + # Create initial server.log file for artifact upload + echo "Safe Inputs MCP Server Log" > /tmp/gh-aw/safe-inputs/logs/server.log + echo "Start time: $(date)" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "===========================================" >> /tmp/gh-aw/safe-inputs/logs/server.log + echo "" >> /tmp/gh-aw/safe-inputs/logs/server.log + # Start the HTTP server in the background + echo "Starting safe-inputs MCP HTTP server..." + node mcp-server.cjs >> /tmp/gh-aw/safe-inputs/logs/server.log 2>&1 & + SERVER_PID=$! + echo "Started safe-inputs MCP server with PID $SERVER_PID" # Wait for server to be ready (max 10 seconds) - echo 'Waiting for safe-inputs MCP server to be ready...' + echo "Waiting for server to become ready..." for i in {1..10}; do - # Check if container is still running - if ! docker ps | grep -q safeinputs; then - echo "ERROR: Safe-inputs container has stopped" - docker logs safeinputs || true + # Check if process is still running + if ! kill -0 $SERVER_PID 2>/dev/null; then + echo "ERROR: Server process $SERVER_PID has died" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log exit 1 fi - - # Check if server is responding (using container name on the network) - if docker run --rm --network gh-aw-network curlimages/curl:latest \ - curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then + # Check if server is responding + if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health > /dev/null 2>&1; then echo "Safe Inputs MCP server is ready (attempt $i/10)" break fi - if [ $i -eq 10 ]; then echo "ERROR: Safe Inputs MCP server failed to start after 10 seconds" - docker logs safeinputs || true + echo "Process status: $(ps aux | grep '[m]cp-server.cjs' || echo 'not running')" + echo "Server log contents:" + cat /tmp/gh-aw/safe-inputs/logs/server.log + echo "Checking port availability:" + netstat -tuln | grep $GH_AW_SAFE_INPUTS_PORT || echo "Port $GH_AW_SAFE_INPUTS_PORT not listening" exit 1 fi - echo "Waiting for server... (attempt $i/10)" sleep 1 done + # Output the configuration for the MCP client + echo "port=$GH_AW_SAFE_INPUTS_PORT" >> $GITHUB_OUTPUT + echo "api_key=$GH_AW_SAFE_INPUTS_API_KEY" >> $GITHUB_OUTPUT - name: Setup MCPs env: diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 4780434e33..8217a95908 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -221,12 +221,6 @@ const SafeInputsMCPServerID = "safeinputs" // SafeInputsMCPVersion is the version of the safe-inputs MCP server const SafeInputsMCPVersion = "1.0.0" -// SafeInputsDockerNetwork is the name of the Docker network for safe-inputs -const SafeInputsDockerNetwork = "gh-aw-network" - -// SafeInputsContainerName is the name of the safe-inputs Docker container -const SafeInputsContainerName = "safeinputs" - // Step IDs for pre-activation job const CheckMembershipStepID = "check_membership" const CheckStopTimeStepID = "check_stop_time" diff --git a/pkg/workflow/mcp_renderer.go b/pkg/workflow/mcp_renderer.go index ed04a3cf5a..f88ea71ba1 100644 --- a/pkg/workflow/mcp_renderer.go +++ b/pkg/workflow/mcp_renderer.go @@ -219,7 +219,7 @@ func (r *MCPConfigRendererUnified) RenderSafeInputsMCP(yaml *strings.Builder, sa } // renderSafeInputsTOML generates Safe Inputs MCP configuration in TOML format -// Uses HTTP transport with localhost (container accessible via port mapping) +// Uses HTTP transport for consistency with JSON format (Copilot/Claude) func (r *MCPConfigRendererUnified) renderSafeInputsTOML(yaml *strings.Builder, safeInputs *SafeInputsConfig) { envVars := getSafeInputsEnvVars(safeInputs) diff --git a/pkg/workflow/mcp_servers.go b/pkg/workflow/mcp_servers.go index d0d52b2edc..58de9b0c66 100644 --- a/pkg/workflow/mcp_servers.go +++ b/pkg/workflow/mcp_servers.go @@ -438,62 +438,24 @@ func (c *Compiler) generateMCPSetup(yaml *strings.Builder, tools map[string]any, yaml.WriteString(" generateSafeInputsConfig({ core, crypto });\n") yaml.WriteString(" \n") - // Step 4: Create Docker network for safe-inputs - yaml.WriteString(" - name: Create Docker Network for Safe Inputs\n") - yaml.WriteString(" run: |\n") - yaml.WriteString(" docker network create " + constants.SafeInputsDockerNetwork + " || true\n") - yaml.WriteString(" echo 'Docker network created: " + constants.SafeInputsDockerNetwork + "'\n") - yaml.WriteString(" \n") - - // Step 5: Start the HTTP server in a Docker container + // Step 4: Start the HTTP server in the background yaml.WriteString(" - name: Start Safe Inputs MCP HTTP Server\n") yaml.WriteString(" id: safe-inputs-start\n") yaml.WriteString(" run: |\n") - yaml.WriteString(" # Build docker run command\n") - yaml.WriteString(" docker run -d --rm --init \\\n") - yaml.WriteString(" --name " + constants.SafeInputsContainerName + " \\\n") - yaml.WriteString(" --network " + constants.SafeInputsDockerNetwork + " \\\n") - yaml.WriteString(" -p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \\\n") - yaml.WriteString(" -e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }} \\\n") - yaml.WriteString(" -e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} \\\n") + yaml.WriteString(" # Set environment variables for the server\n") + yaml.WriteString(" export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }}\n") + yaml.WriteString(" export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }}\n") + yaml.WriteString(" \n") // Pass through environment variables from safe-inputs config envVars := getSafeInputsEnvVars(workflowData.SafeInputs) for _, envVar := range envVars { - yaml.WriteString(fmt.Sprintf(" -e %s=\"${%s}\" \\\n", envVar, envVar)) + yaml.WriteString(fmt.Sprintf(" export %s=\"${%s}\"\n", envVar, envVar)) } - - yaml.WriteString(" -v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs \\\n") - yaml.WriteString(" -w /tmp/gh-aw/safe-inputs \\\n") - yaml.WriteString(" node:" + string(constants.DefaultNodeVersion) + " \\\n") - yaml.WriteString(" node mcp-server.cjs\n") yaml.WriteString(" \n") - yaml.WriteString(" # Wait for server to be ready (max 10 seconds)\n") - yaml.WriteString(" echo 'Waiting for safe-inputs MCP server to be ready...'\n") - yaml.WriteString(" for i in {1..10}; do\n") - yaml.WriteString(" # Check if container is still running\n") - yaml.WriteString(" if ! docker ps | grep -q " + constants.SafeInputsContainerName + "; then\n") - yaml.WriteString(" echo \"ERROR: Safe-inputs container has stopped\"\n") - yaml.WriteString(" docker logs " + constants.SafeInputsContainerName + " || true\n") - yaml.WriteString(" exit 1\n") - yaml.WriteString(" fi\n") - yaml.WriteString(" \n") - yaml.WriteString(" # Check if server is responding (using container name on the network)\n") - yaml.WriteString(" if docker run --rm --network " + constants.SafeInputsDockerNetwork + " curlimages/curl:latest \\\n") - yaml.WriteString(" curl -s -f http://" + constants.SafeInputsContainerName + ":${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health > /dev/null 2>&1; then\n") - yaml.WriteString(" echo \"Safe Inputs MCP server is ready (attempt $i/10)\"\n") - yaml.WriteString(" break\n") - yaml.WriteString(" fi\n") - yaml.WriteString(" \n") - yaml.WriteString(" if [ $i -eq 10 ]; then\n") - yaml.WriteString(" echo \"ERROR: Safe Inputs MCP server failed to start after 10 seconds\"\n") - yaml.WriteString(" docker logs " + constants.SafeInputsContainerName + " || true\n") - yaml.WriteString(" exit 1\n") - yaml.WriteString(" fi\n") - yaml.WriteString(" \n") - yaml.WriteString(" echo \"Waiting for server... (attempt $i/10)\"\n") - yaml.WriteString(" sleep 1\n") - yaml.WriteString(" done\n") + + // Use the embedded shell script to start the server + WriteShellScriptToYAML(yaml, startSafeInputsServerScript, " ") yaml.WriteString(" \n") } diff --git a/pkg/workflow/safe_inputs.go b/pkg/workflow/safe_inputs.go index 0faf76280c..ed560af100 100644 --- a/pkg/workflow/safe_inputs.go +++ b/pkg/workflow/safe_inputs.go @@ -587,8 +587,7 @@ func renderSafeInputsMCPConfigWithOptions(yaml *strings.Builder, safeInputs *Saf // Add type field for HTTP (required by MCP specification for HTTP transport) yaml.WriteString(" \"type\": \"http\",\n") - // HTTP URL using localhost (port-mapped from container) - // Container is accessible via localhost from the host, and via container name from other containers on the network + // HTTP URL using environment variable if includeCopilotFields { // Copilot format: backslash-escaped shell variable reference yaml.WriteString(" \"url\": \"http://localhost:\\${GH_AW_SAFE_INPUTS_PORT}\",\n") diff --git a/pkg/workflow/safe_inputs_http_integration_test.go b/pkg/workflow/safe_inputs_http_integration_test.go index f08dee316b..f7a9ff2595 100644 --- a/pkg/workflow/safe_inputs_http_integration_test.go +++ b/pkg/workflow/safe_inputs_http_integration_test.go @@ -54,7 +54,6 @@ Test safe-inputs HTTP server // Verify that the HTTP server configuration steps are generated expectedSteps := []string{ "Generate Safe Inputs MCP Server Config", - "Create Docker Network for Safe Inputs", "Start Safe Inputs MCP HTTP Server", "Setup MCPs", } @@ -65,18 +64,6 @@ Test safe-inputs HTTP server } } - // Verify docker network creation - dockerNetworkChecks := []string{ - "docker network create gh-aw-network", - "Docker network created: gh-aw-network", - } - - for _, check := range dockerNetworkChecks { - if !strings.Contains(yamlStr, check) { - t.Errorf("Expected docker network creation content not found: %q", check) - } - } - // Verify API key generation step uses github-script apiKeyGenChecks := []string{ "uses: actions/github-script@", @@ -90,18 +77,12 @@ Test safe-inputs HTTP server } } - // Verify Docker container startup with port mapping + // Verify HTTP server startup serverStartupChecks := []string{ - "docker run -d --rm --init", - "--name safeinputs", - "--network gh-aw-network", - "-p ${{ steps.safe-inputs-config.outputs.safe_inputs_port }}:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}", - "-e GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }}", - "-e GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }}", - "-v /tmp/gh-aw/safe-inputs:/tmp/gh-aw/safe-inputs", - "-w /tmp/gh-aw/safe-inputs", - "node:24", + "export GH_AW_SAFE_INPUTS_PORT=${{ steps.safe-inputs-config.outputs.safe_inputs_port }}", + "export GH_AW_SAFE_INPUTS_API_KEY=${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }}", "node mcp-server.cjs", + "Started safe-inputs MCP server with PID", } for _, check := range serverStartupChecks { @@ -110,13 +91,11 @@ Test safe-inputs HTTP server } } - // Verify health check using docker run with curl on the network + // Verify health check (health endpoint doesn't require auth) healthCheckItems := []string{ - "docker run --rm --network gh-aw-network curlimages/curl:latest", - "curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health", + "curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health", "Safe Inputs MCP server is ready", "ERROR: Safe Inputs MCP server failed to start", - "docker logs safeinputs", } for _, check := range healthCheckItems { @@ -204,10 +183,10 @@ Test safe-inputs with secrets yamlStr := string(lockContent) - // Verify that tool-specific env vars are passed to the Docker container + // Verify that tool-specific env vars are passed to the HTTP server serverEnvVarChecks := []string{ - `-e API_KEY="${API_KEY}"`, - `-e API_SECRET="${API_SECRET}"`, + `export API_KEY="${API_KEY}"`, + `export API_SECRET="${API_SECRET}"`, } for _, check := range serverEnvVarChecks { @@ -343,16 +322,15 @@ Test readiness check yamlStr := string(lockContent) - // Verify readiness check loop using docker with container name on network + // Verify readiness check loop (health endpoint doesn't require auth) readinessChecks := []string{ "for i in {1..10}; do", - "docker run --rm --network gh-aw-network curlimages/curl:latest", - "curl -s -f http://safeinputs:${{ steps.safe-inputs-config.outputs.safe_inputs_port }}/health", + "if curl -s -f http://localhost:$GH_AW_SAFE_INPUTS_PORT/health", "Safe Inputs MCP server is ready", "break", "if [ $i -eq 10 ]; then", "ERROR: Safe Inputs MCP server failed to start after 10 seconds", - "docker logs safeinputs", + "cat /tmp/gh-aw/safe-inputs/logs/server.log", "exit 1", "sleep 1", } diff --git a/pkg/workflow/sh.go b/pkg/workflow/sh.go index fcf0b3f4e5..439cf0a76a 100644 --- a/pkg/workflow/sh.go +++ b/pkg/workflow/sh.go @@ -24,6 +24,9 @@ var createCacheMemoryDirScript string //go:embed sh/create_gh_aw_tmp_dir.sh var createGhAwTmpDirScript string +//go:embed sh/start_safe_inputs_server.sh +var startSafeInputsServerScript string + //go:embed prompts/xpia_prompt.md var xpiaPromptText string