Skip to content
Merged
Show file tree
Hide file tree
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
15 changes: 6 additions & 9 deletions .github/actions/release/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@ inputs:
bucket-name:
description: S3 bucket name
required: true
prod-deployment-hook-token:
description: Token for the webhook that triggers the deployment to production
promotions-token:
description: GitHub App token used to dispatch the production promotion workflow
required: true
prod-deployment-hook-url:
description: URL of the webhook that triggers the deployment to production
required: true
react-app-rpc-token:
description: Infura RPC API token
promotions-repo:
description: Repository hosting the gated production promotion workflows (owner/name)
required: true
react-app-tenderly-org-name:
description: Tenderly simulation organization name
Expand Down Expand Up @@ -59,8 +56,8 @@ runs:
git tag -f last-release
shell: bash
env:
PROD_DEPLOYMENT_HOOK_TOKEN: ${{ inputs.prod-deployment-hook-token }}
PROD_DEPLOYMENT_HOOK_URL: ${{ inputs.prod-deployment-hook-url }}
GH_TOKEN: ${{ inputs.promotions-token }}
PROMOTIONS_REPO: ${{ inputs.promotions-repo }}
BUCKET_NAME: ${{ inputs.bucket-name }}
GITHUB_TOKEN: ${{ inputs.github-token }}
REACT_APP_TENDERLY_ORG_NAME: ${{ inputs.react-app-tenderly-org-name }}
Expand Down
18 changes: 16 additions & 2 deletions .github/workflows/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,26 @@ jobs:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME_STAGING }}
aws-region: ${{ secrets.AWS_DEFAULT_REGION }}

# Minted here because composite-action steps cannot read secrets directly.
# Installation tokens live 60 minutes and the dispatch is the last nx target;
# historical release runs complete in 3-9 minutes, so expiry is not a
# practical concern.
- name: Generate promotions repo token
id: promotions_token
continue-on-error: true
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.PROMOTIONS_APP_ID }}
private-key: ${{ secrets.PROMOTIONS_APP_PRIVATE_KEY }}
repositories: ${{ secrets.PROMOTIONS_REPO }}
permission-actions: write

- name: 'Deploy production'
uses: ./.github/actions/release
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
prod-deployment-hook-token: ${{ secrets.PROD_DEPLOYMENT_HOOK_TOKEN }}
prod-deployment-hook-url: ${{ secrets.PROD_DEPLOYMENT_HOOK_URL }}
promotions-token: ${{ steps.promotions_token.outputs.token }}
promotions-repo: ${{ github.repository_owner }}/${{ secrets.PROMOTIONS_REPO }}
bucket-name: ${{ secrets.STAGING_BUCKET_NAME }}/releases
react-app-tenderly-org-name: ${{ secrets.REACT_APP_TENDERLY_ORG_NAME }}
react-app-tenderly-project-name: ${{ secrets.REACT_APP_TENDERLY_PROJECT_NAME }}
Expand Down
34 changes: 25 additions & 9 deletions scripts/prepare_production_deployment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,33 @@
set -ev

# Only:
# - Security env variables are available.
if [ -n "$PROD_DEPLOYMENT_HOOK_TOKEN" ] && [ -n "$PROD_DEPLOYMENT_HOOK_URL" ]
# - GH_TOKEN and PROMOTIONS_REPO are available.
if [ -n "$GH_TOKEN" ] && [ -n "$PROMOTIONS_REPO" ]
then
APP_NAME="$(basename $(pwd))"
PACKAGE_VERSION=$(sed -nr 's/^\s*\"version": "([0-9]{1,}\.[0-9]{1,}.*)",$/\1/p' package.json)
curl --silent --output /dev/null --write-out "%{http_code}" -X POST \
-F token="$PROD_DEPLOYMENT_HOOK_TOKEN" \
-F ref=master \
-F "variables[TRIGGER_RELEASE_APP_NAME]=$APP_NAME" \
-F "variables[TRIGGER_RELEASE_COMMIT_TAG]=$PACKAGE_VERSION" \
$PROD_DEPLOYMENT_HOOK_URL
# tx-builder promotes via safe-tx-builder-tf (built from safe-wallet-monorepo
# releases) since 2026-03; dispatching it here would only trip the promotion
# workflow's app guard.
if [ "$APP_NAME" = "tx-builder" ]
then
echo "Skipping tx-builder: it deploys via safe-tx-builder-tf"
exit 0
fi
# --ref is required: without it gh resolves the default branch via GraphQL,
# which the app token (actions:write, metadata:read only) is not allowed to do.
# A failed dispatch must not fail this script: it runs mid nx-chain, before
# `git tag -f last-release`, and a hard exit would leave the release half-done.
# The error annotation stays visible on the run; the promotion can be
# dispatched manually from safe-production-promotions.
if ! gh workflow run react-apps-production.yml \
--repo "$PROMOTIONS_REPO" \
--ref main \
-f "app=$APP_NAME" \
-f "tag=$PACKAGE_VERSION"
then
echo "::error::Failed to dispatch production deployment for $APP_NAME $PACKAGE_VERSION"
fi
else
echo "[ERROR] Production deployment could not be prepared"
echo "::warning::Production deployment could not be prepared: GH_TOKEN or PROMOTIONS_REPO missing"
fi
Loading