Skip to content

fix: add nil check before writing to dest in handshake handler #27

fix: add nil check before writing to dest in handshake handler

fix: add nil check before writing to dest in handshake handler #27

name: Build and Deploy Proxy Router
on:
push:
branches: [ main, stg, dev, cicd/* ]
paths: [
'build.sh',
'docker-compose.yml',
'Dockerfile',
'**/*.go',
'**/*.ts',
'**/*.js',
'.github/workflows/build-deploy-proxy-router.yml']
pull_request:
types: [opened, reopened, synchronize]
branches:
- dev
paths:
- 'build.sh'
- 'docker-compose.yml'
- 'Dockerfile'
- '**/*.go'
- '**/*.ts'
- '**/*.js'
- '.github/workflows/build-deploy-proxy-router.yml'
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
Generate-Tag:
runs-on: ubuntu-latest
name: Generate Tag Name
outputs:
tag_name: ${{ steps.gen_tag.outputs.tag_name }}
vtag: ${{ steps.gen_tag.outputs.vtag }}
vfull: ${{ steps.gen_tag.outputs.vfull }}
version: ${{ steps.gen_tag.outputs.version }}
image_name: ${{ steps.config.outputs.image_name }}
environment: ${{ steps.gen_tag.outputs.environment }}
is_cicd_branch: ${{ steps.gen_tag.outputs.is_cicd_branch }}
steps:
- name: Clone repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Generate version tag
id: gen_tag
uses: ./.github/actions/gen-tag
with:
component: proxy-router
major_version: '3'
- name: Config
id: config
run: |
IMAGE_NAME="ghcr.io/lumerin-protocol/proxy-router"
echo "image_name=${IMAGE_NAME}" >> $GITHUB_OUTPUT
echo "✅ Docker Image: ${IMAGE_NAME}:${{ steps.gen_tag.outputs.tag_name }}" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.gen_tag.outputs.is_cicd_branch }}" == "true" ]; then
echo "🔧 CI/CD Test Mode: Build test only" >> $GITHUB_STEP_SUMMARY
fi
Build-Test:
if: |
(github.event_name == 'pull_request' && (github.base_ref == 'main' || github.base_ref == 'stg' || github.base_ref == 'dev')) ||
(github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/cicd/') || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/stg' || github.ref == 'refs/heads/dev'))
runs-on: ubuntu-latest
needs: Generate-Tag
environment: ${{ github.ref == 'refs/heads/main' && 'main' || '' }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Build Docker Image to Test
run: |
BUILDTAG=${{ needs.Generate-Tag.outputs.tag_name }}
BUILDIMAGE=${{ needs.Generate-Tag.outputs.image_name }}
BUILDCOMMIT=${{ github.sha }}
docker build \
--platform linux/amd64 \
--build-arg TAG_NAME=$BUILDTAG \
--build-arg COMMIT=$BUILDCOMMIT \
--load \
-t $BUILDIMAGE:$BUILDTAG \
. || (echo "❌ Failed to build image with tag: $BUILDIMAGE:$BUILDTAG" && exit 1)
echo "✅ Proxy-Router Test Build of $BUILDIMAGE:$BUILDTAG Successful!"
- name: Run Docker Image to Test
run: |
BUILDTAG=${{ needs.Generate-Tag.outputs.tag_name }}
BUILDIMAGE=${{ needs.Generate-Tag.outputs.image_name }}
# Construct Graph URL from org secrets/vars (using DEV for CI testing)
FUTURES_SUBGRAPH_URL="https://gateway.thegraph.com/api/${{ secrets.DEV_GRAPH_APIKEY }}/subgraphs/id/${{ vars.DEV_FUTURES_SUBGRAPH_ID }}"
docker run -d --name proxy-router-test \
-e FUTURES_SUBGRAPH_URL="${FUTURES_SUBGRAPH_URL}" \
-e MULTICALL_ADDRESS=${{ vars.MULTICALL_ADDRESS }} \
-e FUTURES_ADDRESS=${{ vars.FUTURES_ADDRESS }} \
-e FUTURES_VALIDATOR_URL_OVERRIDE=${{ vars.FUTURES_VALIDATOR_URL_OVERRIDE }} \
-e CLONE_FACTORY_ADDRESS=${{ vars.CLONE_FACTORY_ADDRESS }} \
-e ETH_NODE_ADDRESS=${{ vars.ETH_NODE_ADDRESS }} \
-e POOL_ADDRESS=${{ vars.POOL_ADDRESS }} \
-e WEB_ADDRESS=0.0.0.0:8888 \
-e WEB_PUBLIC_URL=http://localhost:8888 \
-e WALLET_PRIVATE_KEY=${{ secrets.WALLET_PRIVATE_KEY }} \
-e LOG_IS_PROD=false \
-e LOG_LEVEL=debug \
-e LOG_JSON=true \
-e ENVIRONMENT=production \
-e HASHRATE_SHARE_TIMEOUT=20m \
-p 8888:8888 \
$BUILDIMAGE:$BUILDTAG || (echo "❌ Failed to start image with tag: $BUILDIMAGE:$BUILDTAG" && exit 1)
timeout=10
while ! curl -s http://localhost:8888/healthcheck >/dev/null; do
((timeout--))
if ((timeout <= 0)); then
echo "📜 Fetching container logs:"
docker logs proxy-router-test
docker stop proxy-router-test
docker rm proxy-router-test
echo "❌ Proxy-Router $BUILDIMAGE:$BUILDTAG failed to start in time"
exit 1
fi
sleep 1
done
echo "✅ Proxy-Router $BUILDIMAGE:$BUILDTAG started successfully!"
VERSION_TAG=$(curl -s http://localhost:8888/healthcheck | jq -r '.version')
echo "📜 Fetching container logs:"
docker logs proxy-router-test
if [ "$VERSION_TAG" == "$BUILDTAG" ]; then
docker stop proxy-router-test
docker rm proxy-router-test
echo "✅ Version tag in container matches the expected tag: $VERSION_TAG"
else
docker stop proxy-router-test
docker rm proxy-router-test
echo "❌ Version tag mismatch: Expected $BUILDTAG, but got $VERSION_TAG"
exit 1 # Prevent failure and continue
fi
echo "✅ Proxy-Router Test Run of $BUILDIMAGE:$BUILDTAG Successful!"
OS-Build:
if: |
needs.Generate-Tag.outputs.is_cicd_branch != 'true' && (
(github.event_name == 'pull_request' && (github.base_ref == 'main' || github.base_ref == 'stg' || github.base_ref == 'dev')) ||
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/stg' || github.ref == 'refs/heads/dev'))
)
runs-on: ubuntu-latest
needs:
- Generate-Tag
- Build-Test
strategy:
matrix:
goos: [linux, darwin, windows]
goarch: [amd64, arm64]
exclude:
- goos: windows
goarch: arm64 # Exclude windows/arm64
fail-fast: false
steps:
- name: Clone repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
cache-dependency-path: |
go.sum
- name: Install dependencies
run: |
go mod download
- name: Set GOOS and GOARCH for cross-compilation
run: |
echo "GOOS=${{ matrix.goos }}" >> $GITHUB_ENV
echo "GOARCH=${{ matrix.goarch }}" >> $GITHUB_ENV
- name: Build
run: |
BUILDTAG=${{ needs.Generate-Tag.outputs.tag_name }}
COMMIT=${{ github.sha }}
go mod tidy
go build \
-ldflags="-s -w \
-X 'github.com/Lumerin-protocol/proxy-router/internal/config.BuildVersion=$BUILDTAG' \
-X 'github.com/Lumerin-protocol/proxy-router/internal/config.Commit=$COMMIT' \
" \
-o ./proxy-router ./cmd || (echo "❌ Failed to build binary" && exit 1)
echo "✅ Proxy-Router Build Successful!"
- name: Pack artifacts
run: |
BUILDTAG="proxy-router-${{ needs.Generate-Tag.outputs.tag_name }}-${{ matrix.goos }}-${{ matrix.goarch }}"
# Adjust artifact extension based on GOOS
if [ "${{ matrix.goos }}" == "windows" ]; then
ARTIFACT="$BUILDTAG.exe"
else
ARTIFACT="$BUILDTAG"
fi
echo "Artifact: $ARTIFACT"
mv ./proxy-router $ARTIFACT # Rename to match OS/arch
chmod +x $ARTIFACT # Ensure it's executable
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
path: ./proxy-router-${{ needs.Generate-Tag.outputs.tag_name }}-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goos == 'windows' && '.exe' || '' }}
name: proxy-router-${{ matrix.goos }}-${{ matrix.goarch }}
Release:
if: |
needs.Generate-Tag.outputs.is_cicd_branch != 'true' &&
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/stg' || github.ref == 'refs/heads/dev'))
needs:
- Generate-Tag
- OS-Build
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: ./artifact
- name: Prepare artifacts
run: |
mkdir -p ./artifact/release
mv ./artifact/*/* ./artifact/release
ls -lah ./artifact/release
- name: Create release
id: create_release
uses: anzz1/action-create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.Generate-Tag.outputs.tag_name }}
prerelease: ${{ github.ref != 'refs/heads/main' }}
- name: Upload release assets
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ needs.Generate-Tag.outputs.tag_name }}
files: ./artifact/release/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GHCR-Build-and-Push:
if: |
needs.Generate-Tag.outputs.is_cicd_branch != 'true' &&
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/stg' || github.ref == 'refs/heads/dev'))
needs:
- Generate-Tag
- Build-Test
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Push Multi-Platform Docker Image
run: |
BUILDTAG=${{ needs.Generate-Tag.outputs.tag_name }}
BUILDIMAGE=${{ needs.Generate-Tag.outputs.image_name }}
BUILDCOMMIT=${{ github.sha }}
docker buildx build \
--platform linux/amd64,linux/arm64 \
--build-arg TAG_NAME=$BUILDTAG \
--build-arg COMMIT=$BUILDCOMMIT \
--push \
-t $BUILDIMAGE:$BUILDTAG \
. || (echo "❌ Failed to push image with tag: $BUILDIMAGE:$BUILDTAG" && exit 1)
echo "✅ Proxy-Router Build and Push of $BUILDIMAGE:$BUILDTAG Successful!"
- name: Optionally Push Latest Tag
if: ${{ github.ref == 'refs/heads/main' }}
run: |
BUILDIMAGE=${{ needs.Generate-Tag.outputs.image_name }}
BUILDTAG=${{ needs.Generate-Tag.outputs.tag_name }}
docker pull $BUILDIMAGE:$BUILDTAG || (echo "❌ Failed to pull image: $BUILDIMAGE:$BUILDTAG" && exit 1)
docker tag $BUILDIMAGE:$BUILDTAG $BUILDIMAGE:latest || (echo "❌ Failed to tag image as :latest" && exit 1)
docker push $BUILDIMAGE:latest || (echo "❌ Failed to push image as :latest" && exit 1)
echo "✅ Proxy-Router Push $BUILDIMAGE:latest Tag Successful!"
AWS-Deploy:
if: |
needs.Generate-Tag.outputs.is_cicd_branch != 'true' &&
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/stg' || github.ref == 'refs/heads/dev'))
needs:
- Generate-Tag
- GHCR-Build-and-Push
runs-on: ubuntu-latest
environment: ${{ github.ref_name == 'main' && 'main' || github.ref_name }}
permissions:
id-token: write
contents: read
steps:
- name: Clone
id: checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install dependencies
run: |
sudo apt-get update && sudo apt-get install -y jq
- name: Determine AWS Environment
id: set_environment
run: |
if [ "${{ github.ref_name }}" == "dev" ]; then
echo "aws_env=dev" >> $GITHUB_ENV
elif [ "${{ github.ref_name }}" == "stg" ]; then
echo "aws_env=stg" >> $GITHUB_ENV
elif [ "${{ github.ref_name }}" == "main" ]; then
echo "aws_env=lmn" >> $GITHUB_ENV
else
echo "This branch is not configured for AWS deployment."
exit 1
fi
echo "aws_region=us-east-1" >> $GITHUB_ENV
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ env.aws_region }}
role-session-name: GitHubActions-ProxyRouter-Deploy
- name: Deploy Proxy Router to ECS
run: |
BUILDTAG="${{ needs.Generate-Tag.outputs.tag_name }}"
BUILDIMAGE="${{ needs.Generate-Tag.outputs.image_name }}"
AWS_ENV="${{ env.aws_env }}"
AWS_REGION="${{ env.aws_region }}"
CLUSTER_NAME="ecs-proxy-router-${AWS_ENV}-use1"
SERVICE_NAME="svc-proxy-router-${AWS_ENV}-use1"
TASK_FAMILY="tsk-proxy-router"
echo "🚀 Deploying ${BUILDIMAGE}:${BUILDTAG} to ${AWS_ENV} environment"
echo "Cluster: ${CLUSTER_NAME}"
echo "Service: ${SERVICE_NAME}"
# Get current task definition
aws ecs describe-task-definition \
--task-definition ${TASK_FAMILY} \
--region ${AWS_REGION} \
--query 'taskDefinition' > task-def.json
# Update task definition with new image only
# Secrets are pulled at runtime by ECS from Secrets Manager
jq --arg IMAGE "${BUILDIMAGE}:${BUILDTAG}" \
'.containerDefinitions[0].image = $IMAGE |
del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)' \
task-def.json > new-task-def.json
# Register new task definition
NEW_TASK_DEF=$(aws ecs register-task-definition \
--cli-input-json file://new-task-def.json \
--region ${AWS_REGION} \
--query 'taskDefinition.taskDefinitionArn' --output text)
echo "✅ Registered new task definition: ${NEW_TASK_DEF}"
# Update ECS service
aws ecs update-service \
--cluster ${CLUSTER_NAME} \
--service ${SERVICE_NAME} \
--task-definition ${NEW_TASK_DEF} \
--region ${AWS_REGION} \
--force-new-deployment
echo "✅ Proxy Router service updated successfully!"
- name: Deploy Proxy Validator to ECS
run: |
BUILDTAG="${{ needs.Generate-Tag.outputs.tag_name }}"
BUILDIMAGE="${{ needs.Generate-Tag.outputs.image_name }}"
AWS_ENV="${{ env.aws_env }}"
AWS_REGION="${{ env.aws_region }}"
CLUSTER_NAME="ecs-proxy-router-${AWS_ENV}-use1"
SERVICE_NAME="svc-proxy-validator-${AWS_ENV}-use1"
TASK_FAMILY="tsk-proxy-validator"
echo "🚀 Deploying ${BUILDIMAGE}:${BUILDTAG} to ${AWS_ENV} validator"
echo "Cluster: ${CLUSTER_NAME}"
echo "Service: ${SERVICE_NAME}"
# Get current task definition
aws ecs describe-task-definition \
--task-definition ${TASK_FAMILY} \
--region ${AWS_REGION} \
--query 'taskDefinition' > validator-task-def.json
# Update task definition with new image only
# Secrets are pulled at runtime by ECS from Secrets Manager
jq --arg IMAGE "${BUILDIMAGE}:${BUILDTAG}" \
'.containerDefinitions[0].image = $IMAGE |
del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)' \
validator-task-def.json > new-validator-task-def.json
# Register new task definition
NEW_TASK_DEF=$(aws ecs register-task-definition \
--cli-input-json file://new-validator-task-def.json \
--region ${AWS_REGION} \
--query 'taskDefinition.taskDefinitionArn' --output text)
echo "✅ Registered new task definition: ${NEW_TASK_DEF}"
# Wait 5 minutes for router to stabilize before updating validator
echo "⏳ Waiting 5 minutes before deploying validator..."
sleep 300
# Update ECS service
aws ecs update-service \
--cluster ${CLUSTER_NAME} \
--service ${SERVICE_NAME} \
--task-definition ${NEW_TASK_DEF} \
--region ${AWS_REGION} \
--force-new-deployment
echo "✅ Proxy Validator service updated successfully!"
echo "🎉 Deployment to ${AWS_ENV} complete!"
Notify:
name: 📢 Notify
runs-on: ubuntu-latest
needs: [Generate-Tag, Build-Test, OS-Build, Release, GHCR-Build-and-Push, AWS-Deploy]
if: always() && github.event_name != 'pull_request'
steps:
- name: Checkout (for composite action)
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Determine status
id: status
run: |
if [ "${{ needs.Generate-Tag.outputs.is_cicd_branch }}" == "true" ]; then
# For cicd branches, success if Build-Test passed
if [ "${{ needs.Build-Test.result }}" == "success" ]; then
echo "status=success" >> $GITHUB_OUTPUT
else
echo "status=failure" >> $GITHUB_OUTPUT
fi
elif [ "${{ needs.AWS-Deploy.result }}" == "success" ]; then
echo "status=success" >> $GITHUB_OUTPUT
elif [ "${{ needs.AWS-Deploy.result }}" == "failure" ] || [ "${{ needs.GHCR-Build-and-Push.result }}" == "failure" ] || [ "${{ needs.Build-Test.result }}" == "failure" ]; then
echo "status=failure" >> $GITHUB_OUTPUT
elif [ "${{ needs.AWS-Deploy.result }}" == "cancelled" ]; then
echo "status=cancelled" >> $GITHUB_OUTPUT
else
echo "status=skipped" >> $GITHUB_OUTPUT
fi
- name: Send Slack notification
uses: ./.github/actions/slack-notify
with:
status: ${{ steps.status.outputs.status }}
environment: ${{ needs.Generate-Tag.outputs.environment }}
service_name: 'Proxy Seller & Validator'
version: ${{ needs.Generate-Tag.outputs.tag_name }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
github_token: ${{ secrets.GITHUB_TOKEN }}
image_tag: ${{ needs.Generate-Tag.outputs.is_cicd_branch != 'true' && format('{0}:{1}', needs.Generate-Tag.outputs.image_name, needs.Generate-Tag.outputs.tag_name) || '' }}
additional_info: '${{ needs.Generate-Tag.outputs.is_cicd_branch == ''true'' && ''*Mode:* CI/CD Test (build test only)'' || ''*Services:* Proxy Router + Proxy Validator'' }}'