Skip to content

Commit d1aa049

Browse files
ci(lore-0390): retire staging fossil + add prod deploy template
deploy-staging.yml + scripts/staging-deploy.sh were fossils (us-east-1 staging env gone: 0 stacks; dead staging-* tag trigger; bin/staging.ts + staging.json already removed). Add deploy-production.yml as a dispatch-only POST-LAUNCH template: build -> cdk diff -> manual approval gate -> per-stack deploy -> smoke. See task lore-0390.
1 parent f5bd688 commit d1aa049

3 files changed

Lines changed: 142 additions & 223 deletions

File tree

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: Deploy Production
2+
3+
# ─────────────────────────────────────────────────────────────────────────────
4+
# POST-LAUNCH TEMPLATE — deliberately NOT wired in.
5+
#
6+
# • Trigger is `workflow_dispatch` ONLY (manual, deliberate). Do NOT add
7+
# push/tag auto-triggers until the team has decided a release cadence.
8+
# • Safety model: build → `cdk diff` (prints) → MANUAL APPROVAL GATE
9+
# (GitHub `production` environment: required reviewers) → `cdk deploy`.
10+
# • Deploys the CHOSEN stack(s) from an input, NOT a blind `--all`. This
11+
# mirrors the operational lesson that a full compute deploy ships unrelated
12+
# drift (indexer/enrichment) as a side effect — always diff + pick a stack.
13+
#
14+
# Prerequisites before enabling (do these post-launch, deliberately):
15+
# 1. Create GitHub environment `production` with REQUIRED REVIEWERS — that is
16+
# the human gate between the printed diff and the actual deploy.
17+
# 2. Secrets: AWS_DEPLOY_ROLE_ARN (prod deploy role), AWS_ACCOUNT_ID.
18+
# 3. Region is eu-central-1 (where prod lives). CloudFront ACM certs remain
19+
# us-east-1 internally, but the stacks deploy to eu-central-1 via
20+
# production.json — do not change aws-region here.
21+
# 4. Frontend CONTENT (SPA build → S3 sync → CloudFront invalidation) is a
22+
# separate step (`make deploy-production-web`); this workflow deploys the
23+
# CDK stacks, not the SPA bundle. Deploy the `Delivery` stack here, then
24+
# run the web content sync separately.
25+
# ─────────────────────────────────────────────────────────────────────────────
26+
27+
on:
28+
workflow_dispatch:
29+
inputs:
30+
stacks:
31+
description: 'Stack id(s) to deploy, space-separated. Prefer ONE stack; avoid a blind --all.'
32+
required: true
33+
default: 'Explorer-production-ApiGateway'
34+
exclusively:
35+
description: 'Deploy ONLY the named stack(s), skip dependency stacks (--exclusively)'
36+
type: boolean
37+
default: true
38+
39+
concurrency:
40+
group: deploy-production
41+
cancel-in-progress: false
42+
43+
permissions:
44+
id-token: write
45+
contents: read
46+
47+
jobs:
48+
diff:
49+
name: Build + cdk diff (REVIEW this before approving the deploy)
50+
runs-on: ubuntu-latest
51+
steps:
52+
- uses: actions/checkout@v4
53+
with:
54+
fetch-depth: 0
55+
- uses: actions/setup-node@v4
56+
id: setup-node
57+
with:
58+
node-version-file: .nvmrc
59+
cache: npm
60+
- name: Cache node_modules
61+
id: cache-node-modules
62+
uses: actions/cache@v4
63+
with:
64+
path: node_modules
65+
key: node-modules-${{ runner.os }}-${{ runner.arch }}-node${{ steps.setup-node.outputs.node-version }}-${{ hashFiles('package-lock.json') }}
66+
- name: Install dependencies
67+
if: steps.cache-node-modules.outputs.cache-hit != 'true'
68+
run: npm ci
69+
- uses: dtolnay/rust-toolchain@stable
70+
- uses: Swatinem/rust-cache@v2
71+
- name: Install cargo-lambda
72+
run: pip3 install cargo-lambda
73+
- uses: aws-actions/configure-aws-credentials@v4
74+
with:
75+
role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
76+
aws-region: eu-central-1
77+
- name: Build CDK app
78+
run: npx nx build @rumblefish/soroban-block-explorer-aws-cdk
79+
- name: cdk diff — what WOULD change (review before approving deploy)
80+
run: |
81+
cd infra && npx cdk --app "node dist/bin/production.js" \
82+
diff ${{ inputs.stacks }} ${{ inputs.exclusively && '--exclusively' || '' }}
83+
84+
deploy:
85+
name: CDK deploy (gated on manual approval)
86+
needs: diff
87+
runs-on: ubuntu-latest
88+
# ── The human gate: this job WAITS for a required reviewer to approve in the
89+
# GitHub UI (environment protection rule) before it runs. Configure the
90+
# `production` environment with required reviewers, or this deploys
91+
# unattended. ──
92+
environment: production
93+
steps:
94+
- uses: actions/checkout@v4
95+
with:
96+
fetch-depth: 0
97+
- uses: actions/setup-node@v4
98+
id: setup-node
99+
with:
100+
node-version-file: .nvmrc
101+
cache: npm
102+
- name: Cache node_modules
103+
id: cache-node-modules
104+
uses: actions/cache@v4
105+
with:
106+
path: node_modules
107+
key: node-modules-${{ runner.os }}-${{ runner.arch }}-node${{ steps.setup-node.outputs.node-version }}-${{ hashFiles('package-lock.json') }}
108+
- name: Install dependencies
109+
if: steps.cache-node-modules.outputs.cache-hit != 'true'
110+
run: npm ci
111+
- uses: dtolnay/rust-toolchain@stable
112+
- uses: Swatinem/rust-cache@v2
113+
- name: Install cargo-lambda
114+
run: pip3 install cargo-lambda
115+
- uses: aws-actions/configure-aws-credentials@v4
116+
with:
117+
role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
118+
aws-region: eu-central-1
119+
- name: Build CDK app
120+
run: npx nx build @rumblefish/soroban-block-explorer-aws-cdk
121+
- name: CDK deploy (approval already granted via the environment gate)
122+
run: |
123+
cd infra && npx cdk --app "node dist/bin/production.js" \
124+
deploy ${{ inputs.stacks }} ${{ inputs.exclusively && '--exclusively' || '' }} \
125+
--require-approval never
126+
env:
127+
CDK_DEFAULT_ACCOUNT: ${{ secrets.AWS_ACCOUNT_ID }}
128+
- name: Smoke test — API /health (edge-lock-exempt, no secret needed)
129+
run: |
130+
API=$(aws cloudformation describe-stacks --region eu-central-1 \
131+
--stack-name Explorer-production-ApiGateway \
132+
--query 'Stacks[0].Outputs[?OutputKey==`ApiEndpoint`].OutputValue' \
133+
--output text)
134+
curl -f --retry 3 --retry-delay 5 "${API%/}/health"
135+
- name: Smoke test — Frontend (public, no basic-auth on prod)
136+
run: |
137+
CODE=$(curl -s -o /dev/null -w '%{http_code}' --retry 3 --retry-delay 5 \
138+
https://sorobanscan.rumblefish.dev/)
139+
if [ "$CODE" != "200" ]; then
140+
echo "::error::frontend smoke failed: HTTP ${CODE}"; exit 1
141+
fi
142+
echo "frontend smoke OK: HTTP ${CODE}"

.github/workflows/deploy-staging.yml

Lines changed: 0 additions & 183 deletions
This file was deleted.

scripts/staging-deploy.sh

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)