Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
290 changes: 290 additions & 0 deletions .github-new/workflows/deploy-network.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
# 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
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
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
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
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
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
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

# Construct prover-agent image using the same tag as the aztec image,
# since both are published together for official builds (incl. nightlies).
# Using bare `inputs.semver` dropped the `-nightly.YYYYMMDD-amd64` suffix
# and made the prover-agent ImagePullBackOff every nightly deploy.
IMAGE_TAG="${AZTEC_DOCKER_IMAGE##*:}"
echo "PROVER_AGENT_DOCKER_IMAGE=aztecprotocol/aztec-prover-agent:$IMAGE_TAG" >> $GITHUB_ENV

- 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 }}
Loading