11name : Soroban Runtime Guard Deployment
22
33on :
4- # Pruned to manual-only: this workflow was persistently red on push/PR/schedule.
5- # Run on demand from the Actions tab.
6- workflow_dispatch : {}
4+ workflow_dispatch :
5+ inputs :
6+ target :
7+ description : ' Deployment target network'
8+ required : true
9+ default : ' testnet'
10+ type : choice
11+ options :
12+ - testnet
13+ - mainnet
14+ dry_run :
15+ description : ' Perform a dry run without broadcasting'
16+ required : true
17+ default : ' true'
18+ type : choice
19+ options :
20+ - ' true'
21+ - ' false'
22+ ref :
23+ description : ' Git ref to deploy (branch, tag, or SHA)'
24+ required : false
25+ default : ' '
26+ type : string
27+
728env :
829 CARGO_TERM_COLOR : always
930 RUST_BACKTRACE : 1
1031 FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 : true
1132
1233jobs :
13- build-and-deploy :
14- name : Build & Deploy Runtime Guard Wrapper
34+ # ── Shared build — produces the WASM artifact ──────────────────────────────
35+ build :
36+ name : Build Runtime Guard Wrapper
1537 runs-on : ubuntu-latest
1638 permissions :
1739 contents : read
18- deployments : write
19- checks : write
2040
2141 steps :
2242 - name : Checkout repository
2343 uses : actions/checkout@v6
44+ with :
45+ ref : ${{ github.event.inputs.ref || github.ref }}
2446
2547 - name : Install stable Rust toolchain
2648 uses : dtolnay/rust-toolchain@stable
7092 fi
7193 echo "WASM size: $(du -h "$WASM_PATH" | cut -f1)"
7294 echo "WASM_PATH=$WASM_PATH" >> $GITHUB_ENV
95+ echo "WASM_HASH=$(sha256sum "$WASM_PATH" | awk '{print $1}')" >> $GITHUB_ENV
96+
97+ - name : Upload WASM artifact
98+ uses : actions/upload-artifact@v6
99+ with :
100+ name : runtime-guard-wrapper-wasm
101+ path : target/wasm32-unknown-unknown/release/runtime_guard_wrapper.wasm
102+ retention-days : 7
103+
104+ # ── Testnet deploy (existing path) ─────────────────────────────────────────
105+ testnet-deploy :
106+ name : Deploy to Soroban Testnet
107+ runs-on : ubuntu-latest
108+ needs : build
109+ if : github.event.inputs.target == 'testnet'
110+ permissions :
111+ contents : read
112+ deployments : write
113+ checks : write
114+
115+ steps :
116+ - name : Checkout repository
117+ uses : actions/checkout@v6
118+
119+ - name : Install Soroban CLI
120+ run : |
121+ sudo apt-get update
122+ sudo apt-get install -y libdbus-1-dev libudev-dev pkg-config
123+ export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig:$PKG_CONFIG_PATH
124+ echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH" >> $GITHUB_ENV
125+ cargo install --locked soroban-cli || true
126+
127+ - name : Download WASM artifact
128+ uses : actions/download-artifact@v6
129+ with :
130+ name : runtime-guard-wrapper-wasm
131+ path : target/wasm32-unknown-unknown/release/
73132
74133 - name : Show Soroban network info
75134 run : |
@@ -83,81 +142,77 @@ jobs:
83142 echo "present=true" >> "$GITHUB_OUTPUT"
84143 else
85144 echo "present=false" >> "$GITHUB_OUTPUT"
86- echo "::warning::SOROBAN_SECRET_KEY secret is not configured — deployment steps will be skipped. Add the secret to the repository to enable live deployments. "
145+ echo "::warning::SOROBAN_SECRET_KEY secret is not configured — deployment steps will be skipped."
87146 fi
88147 env :
89148 SOROBAN_SECRET_KEY : ${{ secrets.SOROBAN_SECRET_KEY }}
90149
91150 - name : Deploy to Soroban testnet (Dry Run)
92151 if : github.event.inputs.dry_run == 'true' && steps.check-key.outputs.present == 'true'
93152 run : |
94- bash scripts/deploy-soroban-testnet .sh \
153+ bash scripts/deploy.sh \
95154 --network testnet \
96155 --dry-run \
97- --debug
156+ --wasm target/wasm32-unknown-unknown/release/runtime_guard_wrapper.wasm
98157 env :
99158 SOROBAN_SECRET_KEY : ${{ secrets.SOROBAN_SECRET_KEY }}
100- SOROBAN_ACCOUNT_ID : ${{ secrets.SOROBAN_ACCOUNT_ID }}
101159
102160 - name : Deploy to Soroban testnet
103161 if : github.event.inputs.dry_run != 'true' && steps.check-key.outputs.present == 'true'
104162 run : |
105- bash scripts/deploy-soroban-testnet .sh \
163+ bash scripts/deploy.sh \
106164 --network testnet \
107- --interval 300 \
108- --no-continuous \
109- --debug
165+ --wasm target/wasm32-unknown-unknown/release/runtime_guard_wrapper.wasm
110166 env :
111167 SOROBAN_SECRET_KEY : ${{ secrets.SOROBAN_SECRET_KEY }}
112- SOROBAN_ACCOUNT_ID : ${{ secrets.SOROBAN_ACCOUNT_ID }}
113168 timeout-minutes : 30
114169
170+ - name : Continuous validation
171+ if : github.event.inputs.dry_run != 'true' && steps.check-key.outputs.present == 'true'
172+ run : |
173+ echo "Running continuous validation checks..."
174+ if [ -f ".deployment-manifest.json" ]; then
175+ CONTRACTS=$(jq -r '.deployments[].contract_id' .deployment-manifest.json)
176+ for CID in $CONTRACTS; do
177+ echo "Validating: $CID"
178+ if soroban contract invoke --id "$CID" --network testnet -- health_check; then
179+ echo "✓ Health check passed"
180+ else
181+ echo "✗ Health check failed"
182+ exit 1
183+ fi
184+ done
185+ fi
186+ env :
187+ SOROBAN_SECRET_KEY : ${{ secrets.SOROBAN_SECRET_KEY }}
188+ SOROBAN_ACCOUNT_ID : ${{ secrets.SOROBAN_ACCOUNT_ID }}
189+
115190 - name : Upload deployment manifest
116191 if : always()
117192 uses : actions/upload-artifact@v6
118193 with :
119- name : deployment-manifest-${{ github.run_id }}
194+ name : deployment-manifest-testnet- ${{ github.run_id }}
120195 path : .deployment-manifest.json
121196 retention-days : 30
122197
123- - name : Upload deployment log
124- if : always()
125- uses : actions/upload-artifact@v6
126- with :
127- name : deployment-log-${{ github.run_id }}
128- path : .deployment.log
129- retention-days : 30
130-
131- - name : Parse deployment results
132- if : always()
133- run : |
134- if [ -f ".deployment-manifest.json" ]; then
135- echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY
136- echo "" >> $GITHUB_STEP_SUMMARY
137- jq '.deployments[] | "- **\(.name)**: `\(.contract_id)` (\(.status))"' \
138- .deployment-manifest.json >> $GITHUB_STEP_SUMMARY
139- echo "" >> $GITHUB_STEP_SUMMARY
140- echo "Last updated: $(jq -r '.last_updated' .deployment-manifest.json)" >> $GITHUB_STEP_SUMMARY
141- fi
142-
143- continuous-validation :
144- name : Continuous Validation
198+ # ── Mainnet deploy (gated by GitHub Environment + manual approval) ───────
199+ mainnet-deploy :
200+ name : Deploy to Soroban Mainnet
145201 runs-on : ubuntu-latest
146- needs : build-and-deploy
147- if : success() && github.ref == 'refs/heads/main'
202+ needs : build
203+ if : github.event.inputs.target == 'mainnet'
204+ environment :
205+ name : mainnet
206+ url : https://stellar.expert/explorer
148207 permissions :
149208 contents : read
150209 deployments : write
210+ checks : write
151211
152212 steps :
153213 - name : Checkout repository
154214 uses : actions/checkout@v6
155215
156- - name : Download deployment manifest
157- uses : actions/download-artifact@v6
158- with :
159- name : deployment-manifest-${{ github.run_id }}
160-
161216 - name : Install Soroban CLI
162217 run : |
163218 sudo apt-get update
@@ -166,95 +221,106 @@ jobs:
166221 echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH" >> $GITHUB_ENV
167222 cargo install --locked soroban-cli || true
168223
169- - name : Run continuous validation checks
224+ - name : Download WASM artifact
225+ uses : actions/download-artifact@v6
226+ with :
227+ name : runtime-guard-wrapper-wasm
228+ path : target/wasm32-unknown-unknown/release/
229+
230+ - name : Show Soroban network info
170231 run : |
171- echo "Running continuous validation checks..."
172-
232+ soroban network ls
233+ soroban network info --network mainnet
234+
235+ - name : Check mainnet deployment secrets
236+ id : check-key
237+ run : |
238+ if [[ -n "${SOROBAN_MAINNET_SECRET_KEY:-}" ]]; then
239+ echo "present=true" >> "$GITHUB_OUTPUT"
240+ else
241+ echo "present=false" >> "$GITHUB_OUTPUT"
242+ echo "::error::SOROBAN_MAINNET_SECRET_KEY is not configured — aborting."
243+ exit 1
244+ fi
245+ env :
246+ SOROBAN_MAINNET_SECRET_KEY : ${{ secrets.SOROBAN_MAINNET_SECRET_KEY }}
247+
248+ - name : Dry-run first (preflight simulation)
249+ run : |
250+ bash scripts/deploy.sh \
251+ --network mainnet \
252+ --confirm-mainnet \
253+ --dry-run \
254+ --wasm target/wasm32-unknown-unknown/release/runtime_guard_wrapper.wasm
255+ env :
256+ SOROBAN_SECRET_KEY : ${{ secrets.SOROBAN_MAINNET_SECRET_KEY }}
257+
258+ - name : Deploy to Soroban mainnet
259+ run : |
260+ bash scripts/deploy.sh \
261+ --network mainnet \
262+ --confirm-mainnet \
263+ --wasm target/wasm32-unknown-unknown/release/runtime_guard_wrapper.wasm
264+ env :
265+ SOROBAN_SECRET_KEY : ${{ secrets.SOROBAN_MAINNET_SECRET_KEY }}
266+ timeout-minutes : 30
267+
268+ - name : Continuous validation
269+ run : |
270+ echo "Running mainnet validation checks..."
173271 if [ -f ".deployment-manifest.json" ]; then
174272 CONTRACTS=$(jq -r '.deployments[].contract_id' .deployment-manifest.json)
175-
176- for CONTRACT_ID in $CONTRACTS; do
177- echo ""
178- echo "Validating contract: $CONTRACT_ID"
179-
180- # Health check
181- if soroban contract invoke \
182- --id "$CONTRACT_ID" \
183- --network testnet \
184- -- health_check; then
185- echo "✓ Health check passed for $CONTRACT_ID"
273+ for CID in $CONTRACTS; do
274+ echo "Validating: $CID"
275+ if soroban contract invoke --id "$CID" --network mainnet -- health_check; then
276+ echo "✓ Health check passed"
186277 else
187- echo "✗ Health check failed for $CONTRACT_ID "
278+ echo "✗ Health check failed"
188279 exit 1
189280 fi
190-
191- # Get stats
192- if soroban contract invoke \
193- --id "$CONTRACT_ID" \
194- --network testnet \
195- -- get_stats 2>/dev/null; then
196- echo "✓ Stats retrieved for $CONTRACT_ID"
197- fi
198281 done
199282 fi
200283 env :
201- SOROBAN_SECRET_KEY : ${{ secrets.SOROBAN_SECRET_KEY }}
202- SOROBAN_ACCOUNT_ID : ${{ secrets.SOROBAN_ACCOUNT_ID }}
284+ SOROBAN_SECRET_KEY : ${{ secrets.SOROBAN_MAINNET_SECRET_KEY }}
203285
204- - name : Generate validation report
286+ - name : Upload deployment manifest
205287 if : always()
206- run : |
207- echo "## Continuous Validation Report" >> $GITHUB_STEP_SUMMARY
208- echo "" >> $GITHUB_STEP_SUMMARY
209- echo "- Timestamp: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
210- echo "- Network: testnet" >> $GITHUB_STEP_SUMMARY
211- echo "- Status: Success" >> $GITHUB_STEP_SUMMARY
288+ uses : actions/upload-artifact@v6
289+ with :
290+ name : deployment-manifest-mainnet-${{ github.run_id }}
291+ path : .deployment-manifest.json
292+ retention-days : 90
212293
213- notification :
214- name : Send Deployment Notification
294+ # ── Summary ──────────────────────────────────────────────────────────────
295+ summary :
296+ name : Deployment Summary
215297 runs-on : ubuntu-latest
216- needs : [build-and- deploy, continuous-validation ]
298+ needs : [build, testnet- deploy, mainnet-deploy ]
217299 if : always()
218300 permissions :
219301 checks : write
220302
221303 steps :
222- - name : Determine status
304+ - name : Determine overall status
223305 id : status
224306 run : |
225- if [ " ${{ needs.build-and -deploy.result }}" = " success" ]; then
307+ if [[ ' ${{ needs.testnet-deploy.result }}' == 'success' || '${{ needs.mainnet -deploy.result }}' == ' success' ] ]; then
226308 echo "DEPLOYMENT_STATUS=✅ Success" >> $GITHUB_OUTPUT
227309 echo "DEPLOYMENT_COLOR=0x28a745" >> $GITHUB_OUTPUT
228- else
310+ elif [[ '${{ needs.testnet-deploy.result }}' == 'failure' || '${{ needs.mainnet-deploy.result }}' == 'failure' ]]; then
229311 echo "DEPLOYMENT_STATUS=❌ Failed" >> $GITHUB_OUTPUT
230312 echo "DEPLOYMENT_COLOR=0xdc3545" >> $GITHUB_OUTPUT
313+ else
314+ echo "DEPLOYMENT_STATUS=⏭️ Skipped" >> $GITHUB_OUTPUT
315+ echo "DEPLOYMENT_COLOR=0x6c757d" >> $GITHUB_OUTPUT
231316 fi
232317
233- - name : Create deployment status check
234- uses : actions/github-script@v8
235- with :
236- script : |
237- github.rest.checks.create({
238- owner: context.repo.owner,
239- repo: context.repo.repo,
240- name: 'Soroban Runtime Guard Deployment',
241- head_sha: context.sha,
242- status: '${{ needs.build-and-deploy.result }}' === 'success' ? 'completed' : 'completed',
243- conclusion: '${{ needs.build-and-deploy.result }}' === 'success' ? 'success' : 'failure',
244- output: {
245- title: 'Deployment ${{ steps.status.outputs.DEPLOYMENT_STATUS }}',
246- summary: 'Runtime guard wrapper contract has been deployed to Soroban testnet',
247- text: 'Check the deployment artifacts for detailed logs and manifests.'
248- }
249- });
250-
251318 - name : Post deployment summary
252319 run : |
253- echo "## 🚀 Soroban Runtime Guard Deployment Complete " >> $GITHUB_STEP_SUMMARY
320+ echo "## 🚀 Soroban Runtime Guard Deployment" >> $GITHUB_STEP_SUMMARY
254321 echo "" >> $GITHUB_STEP_SUMMARY
255322 echo "**Status**: ${{ steps.status.outputs.DEPLOYMENT_STATUS }}" >> $GITHUB_STEP_SUMMARY
256- echo "**Network**: testnet" >> $GITHUB_STEP_SUMMARY
323+ echo "**Target**: ${{ github.event.inputs.target || 'testnet' }}" >> $GITHUB_STEP_SUMMARY
324+ echo "**Dry Run**: ${{ github.event.inputs.dry_run || 'true' }}" >> $GITHUB_STEP_SUMMARY
257325 echo "**Timestamp**: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
258326 echo "**Commit**: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
259- echo "" >> $GITHUB_STEP_SUMMARY
260- echo "[View Artifacts](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
0 commit comments