fix(sdk): use sender's protocol version for HTTP signature verificati… #26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy Gateway | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - "gateway/**" | |
| - "packages/agent-world-sdk/src/**" | |
| - "packages/agent-world-sdk/package.json" | |
| workflow_dispatch: | |
| concurrency: | |
| group: deploy-gateway | |
| cancel-in-progress: true | |
| permissions: | |
| id-token: write | |
| contents: read | |
| jobs: | |
| deploy: | |
| name: Build & Deploy Gateway | |
| runs-on: ubuntu-latest | |
| env: | |
| ECR_REPOSITORY: awn-gateway | |
| INSTANCE_ID: i-04670f4d1a72c7d5d | |
| GATEWAY_URL: ${{ vars.GATEWAY_URL || 'https://gateway.agentworlds.ai' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v6 | |
| with: | |
| role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Update Cloudflare DNS | |
| env: | |
| CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }} | |
| CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }} | |
| run: | | |
| GATEWAY_HOST=$(echo "$GATEWAY_URL" | sed 's|^https\?://||' | cut -d'/' -f1) | |
| EC2_IP="${{ vars.EC2_PUBLIC_IP }}" | |
| if [ -z "$EC2_IP" ]; then | |
| echo "::error::EC2_PUBLIC_IP variable is not set. Add it in repo Settings -> Variables." | |
| exit 1 | |
| fi | |
| echo "EC2 public IP: $EC2_IP Gateway: $GATEWAY_HOST" | |
| PAYLOAD="{\"type\":\"A\",\"name\":\"$GATEWAY_HOST\",\"content\":\"$EC2_IP\",\"ttl\":1,\"proxied\":true}" | |
| EXISTING=$(curl -s \ | |
| "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records?type=A&name=$GATEWAY_HOST" \ | |
| -H "Authorization: Bearer $CF_API_TOKEN" \ | |
| -H "Content-Type: application/json") | |
| if ! echo "$EXISTING" | jq -e '.success == true' > /dev/null 2>&1; then | |
| echo "::warning::Cloudflare API error: $(echo "$EXISTING" | jq -rc '.errors // .')" | |
| echo "Skipping DNS update — record may already be correct." | |
| else | |
| RECORD_ID=$(echo "$EXISTING" | jq -r '.result[0].id // empty') | |
| CURRENT_IP=$(echo "$EXISTING" | jq -r '.result[0].content // empty') | |
| if [ "$CURRENT_IP" = "$EC2_IP" ]; then | |
| echo "DNS already up to date ($GATEWAY_HOST → $EC2_IP), skipping update." | |
| elif [ -n "$RECORD_ID" ]; then | |
| curl -s -X PUT \ | |
| "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records/$RECORD_ID" \ | |
| -H "Authorization: Bearer $CF_API_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$PAYLOAD" | jq -c '{success,errors}' | |
| echo "Updated DNS A record $RECORD_ID → $EC2_IP" | |
| else | |
| curl -s -X POST \ | |
| "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \ | |
| -H "Authorization: Bearer $CF_API_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$PAYLOAD" | jq -c '{success,errors}' | |
| echo "Created DNS A record $GATEWAY_HOST → $EC2_IP" | |
| fi | |
| fi | |
| - name: Login to Amazon ECR | |
| id: ecr-login | |
| uses: aws-actions/amazon-ecr-login@v2 | |
| - name: Build & push Docker image | |
| env: | |
| REGISTRY: ${{ steps.ecr-login.outputs.registry }} | |
| run: | | |
| IMAGE="$REGISTRY/$ECR_REPOSITORY" | |
| docker build -f gateway/Dockerfile -t "$IMAGE:${{ github.sha }}" -t "$IMAGE:latest" . | |
| docker push "$IMAGE:${{ github.sha }}" | |
| docker push "$IMAGE:latest" | |
| - name: Deploy via SSM | |
| env: | |
| REGISTRY: ${{ steps.ecr-login.outputs.registry }} | |
| run: | | |
| IMAGE="$REGISTRY/$ECR_REPOSITORY:${{ github.sha }}" | |
| # Build SSM parameters via jq to avoid quoting issues. | |
| # The instance role has ecr-pull permissions, so we use the ECR | |
| # credential helper for authentication instead of the aws CLI. | |
| PARAMS=$(jq -cn \ | |
| --arg pull "docker pull $IMAGE" \ | |
| --arg run "docker run -d --name awn-gateway --restart unless-stopped -p 80:8100 -v /opt/awn-gateway/data:/data -e HTTP_PORT=8100 -e DATA_DIR=/data -e PUBLIC_URL=$GATEWAY_URL -e PUBLIC_ADDR=$(echo $GATEWAY_URL | sed 's|^https\?://||' | cut -d'/' -f1) $IMAGE" \ | |
| '{commands: [ | |
| "command -v amazon-ecr-credential-helper >/dev/null 2>&1 || apt-get install -y amazon-ecr-credential-helper", | |
| "mkdir -p /root/.docker && printf '"'"'{\"credsStore\":\"ecr-login\"}'"'"' > /root/.docker/config.json", | |
| $pull, | |
| "docker stop awn-gateway 2>/dev/null || true", | |
| "docker rm awn-gateway 2>/dev/null || true", | |
| "fuser -k 80/tcp 2>/dev/null || true", | |
| $run | |
| ]}') | |
| COMMAND_ID=$(aws ssm send-command \ | |
| --instance-ids "$INSTANCE_ID" \ | |
| --document-name "AWS-RunShellScript" \ | |
| --parameters "$PARAMS" \ | |
| --region us-east-2 \ | |
| --query "Command.CommandId" \ | |
| --output text) | |
| echo "SSM Command ID: $COMMAND_ID" | |
| sleep 5 | |
| for i in $(seq 1 30); do | |
| if STATUS=$(aws ssm get-command-invocation \ | |
| --command-id "$COMMAND_ID" \ | |
| --instance-id "$INSTANCE_ID" \ | |
| --region us-east-2 \ | |
| --query "Status" \ | |
| --output text 2>&1); then | |
| echo "Attempt $i: Status=$STATUS" | |
| if [ "$STATUS" = "Success" ]; then | |
| echo "Deploy command succeeded" | |
| exit 0 | |
| elif [ "$STATUS" = "Failed" ] || [ "$STATUS" = "Cancelled" ] || [ "$STATUS" = "TimedOut" ]; then | |
| echo "Deploy command failed with status: $STATUS" | |
| aws ssm get-command-invocation \ | |
| --command-id "$COMMAND_ID" \ | |
| --instance-id "$INSTANCE_ID" \ | |
| --region us-east-2 \ | |
| --query "StandardErrorContent" \ | |
| --output text | |
| exit 1 | |
| fi | |
| else | |
| echo "Attempt $i: GetCommandInvocation error (will retry): $STATUS" | |
| fi | |
| sleep 10 | |
| done | |
| echo "Timed out waiting for deploy command" | |
| exit 1 | |
| - name: Health check | |
| run: | | |
| COMMAND_ID=$(aws ssm send-command \ | |
| --instance-ids "$INSTANCE_ID" \ | |
| --document-name "AWS-RunShellScript" \ | |
| --parameters commands='["sleep 5","curl -sf http://localhost/health"]' \ | |
| --region us-east-2 \ | |
| --query "Command.CommandId" \ | |
| --output text) | |
| sleep 15 | |
| STATUS=$(aws ssm get-command-invocation \ | |
| --command-id "$COMMAND_ID" \ | |
| --instance-id "$INSTANCE_ID" \ | |
| --region us-east-2 \ | |
| --query "Status" \ | |
| --output text) | |
| if [ "$STATUS" = "Success" ]; then | |
| echo "Health check passed" | |
| else | |
| echo "Health check failed (status: $STATUS)" | |
| aws ssm get-command-invocation \ | |
| --command-id "$COMMAND_ID" \ | |
| --instance-id "$INSTANCE_ID" \ | |
| --region us-east-2 \ | |
| --query "StandardErrorContent" \ | |
| --output text | |
| exit 1 | |
| fi |