Deploy Network #92
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
| # Low-level workflow to deploy a single network | |
| # This is called by other deployment workflows | |
| name: Deploy Network | |
| on: | |
| workflow_call: | |
| inputs: | |
| network: | |
| description: "Network to deploy (e.g., staging-public, testnet, next-net)" | |
| required: true | |
| type: string | |
| aztec_docker_image: | |
| description: "Full Aztec docker image (e.g., aztecprotocol/aztec:2.3.4). If not set, constructed from semver." | |
| required: false | |
| type: string | |
| semver: | |
| description: "Semver version (e.g., 2.3.4). Used to construct docker image if aztec_docker_image is not set." | |
| required: false | |
| type: string | |
| ref: | |
| description: "Git ref to checkout" | |
| required: false | |
| type: string | |
| namespace: | |
| description: "Kubernetes namespace override (optional, defaults to env file value)" | |
| required: false | |
| type: string | |
| deploy_contracts: | |
| description: "Whether to deploy contracts fresh (true for first patch, false to read from network config)" | |
| required: false | |
| type: boolean | |
| default: false | |
| ha_docker_image: | |
| description: "Full docker image for HA validator nodes (optional, defaults to aztec docker image)" | |
| required: false | |
| type: string | |
| source_tag: | |
| description: "Source tag that triggered this deploy" | |
| required: false | |
| type: string | |
| workflow_dispatch: | |
| inputs: | |
| network: | |
| description: "Network to deploy (e.g., staging-public, staging-ignition, testnet, next-net)" | |
| required: true | |
| type: choice | |
| options: | |
| - next-net | |
| - staging-public | |
| - testnet | |
| - mainnet | |
| aztec_docker_image: | |
| description: "Full Aztec docker image (e.g., aztecprotocol/aztec:2.3.4). If not set, constructed from semver." | |
| required: false | |
| type: string | |
| semver: | |
| description: "Semver version (e.g., 2.3.4). Used to construct docker image if aztec_docker_image is not set." | |
| required: false | |
| type: string | |
| namespace: | |
| description: "Kubernetes namespace override (optional, defaults to env file value)" | |
| required: false | |
| type: string | |
| deploy_contracts: | |
| description: "Whether to deploy contracts fresh (true for first patch, false to read from network config)" | |
| required: false | |
| type: boolean | |
| default: false | |
| ha_docker_image: | |
| description: "Full docker image for HA validator nodes (optional, defaults to aztec docker image)" | |
| required: false | |
| type: string | |
| source_tag: | |
| description: "Source tag that triggered this deploy" | |
| required: false | |
| type: string | |
| concurrency: | |
| group: deploy-network-${{ inputs.network }}-${{ inputs.namespace || inputs.network }}-${{ inputs.aztec_docker_image || inputs.semver }}-${{ github.ref || github.ref_name }} | |
| cancel-in-progress: true | |
| jobs: | |
| deploy-network: | |
| runs-on: ubuntu-latest | |
| env: | |
| GOOGLE_APPLICATION_CREDENTIALS: /tmp/gcp-key.json | |
| outputs: | |
| cluster: ${{ steps.deploy-network.outputs.cluster }} | |
| steps: | |
| - name: Determine checkout ref | |
| id: checkout-ref | |
| run: | | |
| # Use inputs.ref if provided (workflow_call), otherwise use github.ref | |
| if [[ -n "${{ inputs.ref }}" ]]; then | |
| echo "ref=${{ inputs.ref }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "ref=${{ github.ref }}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Checkout | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 | |
| with: | |
| ref: ${{ steps.checkout-ref.outputs.ref }} | |
| fetch-depth: 1 | |
| persist-credentials: false | |
| submodules: recursive # Initialize git submodules for l1-contracts dependencies | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| - name: Validate inputs | |
| run: | | |
| # Validate network | |
| if [[ ! -f "spartan/environments/${{ inputs.network }}.env" ]]; then | |
| echo "Error: Environment file not found for network '${{ inputs.network }}'" | |
| echo "Available networks:" | |
| ls -1 spartan/environments/ | grep -v '\.local\.env$' || echo "No environment files found" | |
| exit 1 | |
| fi | |
| # Require at least one of aztec_docker_image or semver | |
| if [[ -z "${{ inputs.aztec_docker_image }}" && -z "${{ inputs.semver }}" ]]; then | |
| echo "Error: Either 'aztec_docker_image' or 'semver' must be provided" | |
| exit 1 | |
| fi | |
| # Validate semver format if provided | |
| if [[ -n "${{ inputs.semver }}" ]]; then | |
| if ! echo "${{ inputs.semver }}" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-.*)?$'; then | |
| echo "Error: Invalid semver format '${{ inputs.semver }}'. Expected format: X.Y.Z or X.Y.Z-suffix" | |
| exit 1 | |
| fi | |
| fi | |
| # Resolve the docker image | |
| if [[ -n "${{ inputs.aztec_docker_image }}" ]]; then | |
| AZTEC_DOCKER_IMAGE="${{ inputs.aztec_docker_image }}" | |
| else | |
| AZTEC_DOCKER_IMAGE="aztecprotocol/aztec:${{ inputs.semver }}" | |
| fi | |
| echo "AZTEC_DOCKER_IMAGE=$AZTEC_DOCKER_IMAGE" >> $GITHUB_ENV | |
| # Only use the separate prover-agent image for official semver builds; | |
| # for custom images, let the deploy script fall back to AZTEC_DOCKER_IMAGE | |
| if [[ -n "${{ inputs.semver }}" ]]; then | |
| echo "PROVER_AGENT_DOCKER_IMAGE=aztecprotocol/aztec-prover-agent:${{ inputs.semver }}" >> $GITHUB_ENV | |
| fi | |
| - name: Store the GCP key in a file | |
| env: | |
| GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }} | |
| run: | | |
| set +x | |
| umask 077 | |
| printf '%s' "$GCP_SA_KEY" > "$GOOGLE_APPLICATION_CREDENTIALS" | |
| jq -e . "$GOOGLE_APPLICATION_CREDENTIALS" >/dev/null | |
| - name: Setup GCP authentication | |
| run: | | |
| gcloud auth activate-service-account --key-file="$GOOGLE_APPLICATION_CREDENTIALS" | |
| - name: Setup gcloud and install GKE auth plugin | |
| uses: google-github-actions/setup-gcloud@v2 | |
| with: | |
| install_components: "gke-gcloud-auth-plugin" | |
| - name: Setup Terraform | |
| uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 | |
| with: | |
| terraform_version: "1.7.5" | |
| terraform_wrapper: false # Disable the wrapper that adds debug output, this messes with reading terraform output | |
| - name: Setup SSH key for CI Redis | |
| env: | |
| BUILD_INSTANCE_SSH_KEY: ${{ secrets.BUILD_INSTANCE_SSH_KEY }} | |
| run: | | |
| if [ -n "${BUILD_INSTANCE_SSH_KEY:-}" ]; then | |
| mkdir -p ~/.ssh | |
| echo "${BUILD_INSTANCE_SSH_KEY}" | base64 --decode > ~/.ssh/build_instance_key | |
| chmod 600 ~/.ssh/build_instance_key | |
| fi | |
| - name: Deploy network | |
| id: deploy-network | |
| env: | |
| AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| GITHUB_TOKEN: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} | |
| RUN_ID: ${{ github.run_id }} | |
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} | |
| GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} | |
| REF_NAME: ${{ inputs.semver && format('v{0}', inputs.semver) || '' }} | |
| GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} | |
| NAMESPACE: ${{ inputs.namespace }} | |
| AZTEC_DOCKER_IMAGE: ${{ env.AZTEC_DOCKER_IMAGE }} | |
| CREATE_ROLLUP_CONTRACTS: ${{ inputs.deploy_contracts == true && 'true' || '' }} | |
| PROVER_AGENT_DOCKER_IMAGE: ${{ env.PROVER_AGENT_DOCKER_IMAGE || env.AZTEC_DOCKER_IMAGE }} | |
| VALIDATOR_HA_DOCKER_IMAGE: ${{ inputs.ha_docker_image || '' }} | |
| run: | | |
| echo "Deploying network: ${{ inputs.network }}" | |
| echo "Using image: $AZTEC_DOCKER_IMAGE" | |
| echo "Using prover image: $PROVER_AGENT_DOCKER_IMAGE" | |
| echo "Using branch/ref: ${{ steps.checkout-ref.outputs.ref }}" | |
| cd spartan | |
| ./scripts/install_deps.sh | |
| ./scripts/network_deploy.sh "${{ inputs.network }}" | |
| # need to source this for CLUSTER | |
| source "./environments/${{ inputs.network }}.env" | |
| if [ -n "$CLUSTER" ]; then | |
| echo "cluster=$CLUSTER" >> $GITHUB_OUTPUT | |
| else | |
| echo "cluster=" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Step summary | |
| if: always() | |
| run: | | |
| { | |
| echo "## Deploy Network" | |
| echo "" | |
| echo "| Item | Value |" | |
| echo "|------|-------|" | |
| echo "| Network | \`${{ inputs.network }}\` |" | |
| echo "| Docker Image | \`${{ env.AZTEC_DOCKER_IMAGE }}\` |" | |
| echo "| Ref | \`${{ steps.checkout-ref.outputs.ref }}\` |" | |
| if [[ -n "${{ inputs.source_tag }}" ]]; then | |
| echo "| Source Tag | [\`${{ inputs.source_tag }}\`](https://github.com/${{ github.repository }}/releases/tag/${{ inputs.source_tag }}) |" | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Notify Slack and dispatch ClaudeBox on failure | |
| if: failure() | |
| env: | |
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} | |
| GH_TOKEN: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} | |
| run: | | |
| if [ -z "${SLACK_BOT_TOKEN:-}" ]; then | |
| echo "No SLACK_BOT_TOKEN, skipping notification" | |
| exit 0 | |
| fi | |
| CHANNEL="#alerts-${{ inputs.network }}" | |
| RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| TEXT="Deploy Network workflow FAILED for *${{ inputs.network }}* (image ${{ env.AZTEC_DOCKER_IMAGE }}): <${RUN_URL}|View Run> (🤖)" | |
| # Post to Slack and capture timestamp for permalink | |
| RESP=$(curl -sS -X POST https://slack.com/api/chat.postMessage \ | |
| -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ | |
| -H "Content-type: application/json" \ | |
| -d "$(jq -n --arg c "$CHANNEL" --arg t "$TEXT" '{channel:$c, text:$t}')") | |
| echo "Slack response: $RESP" | |
| TS=$(echo "$RESP" | jq -r '.ts // empty') | |
| CHANNEL_ID=$(echo "$RESP" | jq -r '.channel // empty') | |
| LINK="" | |
| if [[ -n "$TS" && -n "$CHANNEL_ID" ]]; then | |
| LINK="https://aztecprotocol.slack.com/archives/$CHANNEL_ID/p${TS//./}" | |
| fi | |
| # Dispatch ClaudeBox to investigate the failure | |
| PROMPT="Deployment of ${{ inputs.network }} (image ${{ env.AZTEC_DOCKER_IMAGE }}) failed. \ | |
| Follow .claude/claudebox/deploy-investigation.md to investigate. \ | |
| GitHub Actions run: ${RUN_URL}. \ | |
| Network: ${{ inputs.network }}. \ | |
| Docker image: ${{ env.AZTEC_DOCKER_IMAGE }}. \ | |
| Git ref: ${{ steps.checkout-ref.outputs.ref }}. \ | |
| Namespace: ${{ inputs.namespace || inputs.network }}. \ | |
| Deploy contracts: ${{ inputs.deploy_contracts }}." | |
| gh workflow run claudebox.yml \ | |
| -f prompt="$PROMPT" \ | |
| -f link="${LINK:-$RUN_URL}" \ | |
| -f target_ref="${{ steps.checkout-ref.outputs.ref }}" || true | |
| update-irm: | |
| needs: deploy-network | |
| if: inputs.network == 'testnet' || inputs.network == 'mainnet' | |
| uses: ./.github/workflows/deploy-irm.yml | |
| secrets: inherit | |
| with: | |
| network: ${{ inputs.network }} | |
| l1_network: ${{ inputs.network == 'mainnet' && 'mainnet' || 'sepolia' }} | |
| cluster: ${{ needs.deploy-network.outputs.cluster }} |