Woodpecker CI migration table — all 86 GHA workflows
Date: 2026-07-04 UTC
ADR: docs/architecture/adr/0135-woodpecker-ci-full-migration-phases3-5.md
Scope: Every .github/workflows/*.yml file + 5 composite actions
Wave D status — 2026-07-07 (#4019)
| Metric | Count |
|---|---|
| Total GHA workflows | 86 |
Retired (moved to .github/workflows-retired/) |
51 |
Still active in .github/workflows/ (WP gap) |
35 |
| Double-run conflicts with WP | 0 |
Retired buckets: Phase 2 (3) + Wave A (31) + RETIRE-GHA-NATIVE (6) + DISABLE/ios-ci (1) + Wave C confirmed (4) + Wave B crons batch 1 (6) (#4067/#4068)
WP gaps remaining: Wave B crons (13 remaining) + Wave C deploy gap (22) — Wave B batch 1 (#4067/#4068) ported 2026-07-07.
Wave B crons batch 1 status (2026-07-07, #4067/#4068):
| GHA workflow | WP pipeline | Cron entry/schedule | GHA retired |
|---|---|---|---|
audit-integrity-cron.yml |
.woodpecker/audit-integrity-cron.yaml |
audit-integrity-cron-nightly (0 2 * * ) + audit-integrity-cron-monthly (30 3 1 * ) |
yes |
audit-reconciler-cron.yml |
.woodpecker/audit-reconciler-cron.yaml |
audit-reconciler-cron (30 3 * * *) |
yes |
account-merge-tombstone-cron.yml |
.woodpecker/account-merge-tombstone-cron.yaml |
account-merge-tombstone-cron (0 4 * * *) |
yes |
trace-integrity-cron.yml |
.woodpecker/trace-integrity-cron.yaml |
trace-integrity-cron (0 2 * * 0, weekly Sun) |
yes |
billing-retention-cron.yml |
.woodpecker/billing-retention-cron.yaml |
billing-retention-cron (0 3 * * *) |
yes |
heroku-config-health-nightly.yml |
.woodpecker/heroku-config-health-nightly.yaml |
heroku-config-health-nightly (0 5 * * *) |
yes |
billing-collector-cron.yml |
.woodpecker/billing-collector-cron.yaml |
NOT registered — PAUSED pending #2159 | no — GHA stays active |
billing-collector-cron.yml active on GHA: schedule was already commented out (PAUSED since 2026-05-15). WP YAML written for event: manual only. Cron registration and GHA retirement deferred until #2159 (Postgres migration) unblocks runtime verification.
Full execution record: docs/architecture/adr/0135-woodpecker-ci-full-migration-phases3-5.md § Wave D execution record.
How to read this table
Bucket:
- MIGRATE — port to a .woodpecker/*.yaml pipeline; wave column shows
which execution wave the port ships in.
- RETIRE-GHA-NATIVE — workflow relies on a GHA-specific trigger or action
(workflow_run, workflow_call, release-please) with no direct WP
equivalent. Column "Replacement in WP" shows what covers the function.
- DISABLE — operator-deferred per ADR-0134. File stays; no WP equivalent
created until the deferred decision is revisited.
- PORT-COMPOSITE — not a workflow file; a composite action ported to a
reusable scripts/ci/wpc_* script used inline by migrated pipelines.
Wave: - Phase 2 (done) — pilot WP pipeline already running and green. - Wave A — PR gates, lint, light push CI, manual-dispatch workflows, and low-risk crons. Entry criterion: Phase 2 complete (✓). - Wave B — heavy CI (postgres service containers), remaining crons, e2e/ZAP tests, and nightly-security-scan full port. Entry criterion: Wave A 7-day soak + postgres service container smoke confirmed on AL2023. - Wave C — deploy/release pipeline, gatekeeper, promote-to-main. Entry criterion: Wave B parity + Console Ops Dispatch sub-card filed and in-flight. - Wave D — decommission (disable + archive GHA files). Entry criterion: Wave C 14-day prod soak.
Section 1 — PORT-COMPOSITE (5 composite actions)
These are .github/actions/*/action.yml files, not workflow files. They have
no direct WP equivalent; each is ported to an inline scripts/ci/wpc_* script
copied by value into every migrated pipeline that needs it.
| GHA composite action | WP replacement | Wave | Notes |
|---|---|---|---|
.github/actions/load-vault-secrets |
scripts/ci/wpc_load_vault_secrets.py |
A | Infisical Universal Auth REST; same-step source pattern (NOT inter-step via WOODPECKER_ENV_FILE — not set in WP v3.16.0 step context, confirmed build #6); see ADR-0135 §1 + docs/architecture/woodpecker-wpc-step-usage.md §1 |
.github/actions/notify-deploy-status |
scripts/ci/wpc_notify_deploy_status.py |
A | Same HMAC callback curl logic; Console deploy-modal integration unchanged |
.github/actions/emit-audit-event |
scripts/ci/wpc_emit_audit_event.py |
A | Same vault → Raptor audit endpoint call |
.github/actions/cloudflare-retry |
scripts/ci/wpc_cloudflare_retry.sh |
A | Same retry loop (5 attempts, quadratic backoff) |
.github/actions/check-deploy-freeze |
scripts/ci/wpc_check_deploy_freeze.sh |
A | Same console freeze-check curl; break-glass env var pattern preserved |
Section 2 — DISABLE (1 workflow)
| GHA workflow file | Bucket | Notes |
|---|---|---|
ios-ci.yml |
DISABLE | Deferred per ADR-0134 locked constraint: no macOS runners in new stack. File kept; WP pipeline not created. Re-evaluate post-migration. |
Section 3 — RETIRE-GHA-NATIVE (6 workflows)
| GHA workflow file | Reason | Replacement in Woodpecker |
|---|---|---|
release.yml |
Uses google-github-actions/release-please-action@v4 — GHA action with no WP equivalent |
gh release create step appended to .woodpecker/promote-release-to-main.yaml after successful release→main push; --generate-notes replaces structured CHANGELOG |
slack-notify.yml |
Uses workflow_run trigger (GHA-native event; no WP equivalent); also targets "CI — main" which no longer exists post-ADR-0115 |
Inline on_failure Slack curl steps added to each WP pipeline that previously relied on this workflow for alerting |
synth-probe-waitlist.yml |
Disabled 2026-06-25 (sends real Postmark email; needs non-reputation send path before re-enable). Formally retired; no WP pipeline created. | None until the non-reputation send path is designed (separate card) |
test-cloudflare-retry-action.yml |
Tests the cloudflare-retry GHA composite action; that action is being ported away. No WP equivalent needed. |
The WP port of the action (wpc_cloudflare_retry.sh) is tested by including it in the ci-pr or lint pipeline and verifying retry behavior |
test-emit-audit-event-action.yml |
Same reasoning — tests GHA composite action being retired | Same — absorbed into pipeline-level smoke testing of the WP port |
test-notify-deploy-status.yml |
Same reasoning — tests GHA composite action being retired | Same |
Section 4 — MIGRATE: full per-workflow table
Phase 2 pilots (already running in WP; GHA counterpart still active during soak)
| GHA workflow file | WP target file | WP trigger | Wave | Notes |
|---|---|---|---|---|
alembic-version-cron.yml |
.woodpecker/alembic-version-check.yaml (exists) |
event: cron — alembic-version-check (08:30 UTC daily) |
Phase 2 done | Pilot complete; close out GHA version in Wave A decommission step |
maxmind-asn-refresh.yml |
.woodpecker/maxmind-asn-refresh.yaml (exists) |
event: cron — maxmind-asn-refresh (02:15 UTC daily) |
Phase 2 done | Pilot complete |
nightly-security-scan.yml |
.woodpecker/security-scan-nightly.yaml (exists — partial) |
event: cron — security-scan-nightly (08:07 UTC daily) |
Wave B (full port) | Pilot runs scanner steps only; issue-filing, GH API calls, Slack-on-failure, and raxx-ops-bot token mint not yet ported. Wave B completes the port. |
Wave A — PR gates, lint, push CI, low-risk crons, manual dispatch
| GHA workflow file | WP target file | Trigger mapping | Vault secrets? | Notes |
|---|---|---|---|---|
antlers-next-ci.yml |
.woodpecker/antlers-next-ci.yaml |
GHA pull_request → WP event: pull_request; GHA push branches:[develop] → WP event: push, branch: develop |
No | Vitest + TSC + lint for frontend/raxx-next/ |
bcp-vault-snapshot-daily.yml |
.woodpecker/bcp-vault-snapshot-daily.yaml |
GHA schedule → WP event: cron (02:00 UTC daily) |
Yes (vault export token) | No postgres; vault access only |
ci-boundary.yml |
.woodpecker/ci-boundary.yaml |
GHA push branches:[develop] → WP event: push, branch: develop |
No | Boundary lint checks; no postgres |
ci-console.yml |
.woodpecker/ci-console.yaml |
GHA push branches:[develop] + pull_request → WP event: [push,pull_request], branch: develop |
No | Console Python lint + tests; no postgres service |
ci-digest-cron.yml |
.woodpecker/ci-digest-cron.yaml |
GHA schedule → WP event: cron (09:00 UTC daily) |
Yes (Slack webhook) | GitHub API calls only; no postgres |
ci-pr.yml |
.woodpecker/ci-pr.yaml |
GHA pull_request → WP event: pull_request |
Yes (Alpaca secrets for smoke) | Critical path — required status check swap in Wave A §4. Postgres service step split to Wave B; non-postgres steps migrate in Wave A |
ci.yml |
.woodpecker/ci-develop.yaml |
GHA push branches:[develop] → WP event: push, branch: develop |
Yes (Alpaca secrets) | Critical path. Postgres backend-tests-postgres job deferred to Wave B. Non-postgres jobs (detect-changes, frontend-tests, velvet-tests) migrate in Wave A |
console-degraded-auto-file.yml |
.woodpecker/console-degraded-auto-file.yaml |
GHA schedule → WP event: cron (every 15 min) |
Yes (CF Access, GH token) | Status check + auto-file; no postgres |
cron-heartbeat-monitor.yml |
.woodpecker/cron-heartbeat-monitor.yaml |
GHA schedule → WP event: cron (hourly) |
No | GitHub API heartbeat; no postgres |
daily-bot-token-smoke.yml |
.woodpecker/daily-bot-token-smoke.yaml |
GHA schedule → WP event: cron (08:00 UTC daily) |
Yes (bot App keys) | Bot token validation; no postgres |
daily-card-groomer.yml |
.woodpecker/daily-card-groomer.yaml |
GHA schedule → WP event: cron (10:00 UTC daily) |
Yes (PM bot keys) | GitHub API + vault; no postgres |
drift-orchestrator-cron.yml |
.woodpecker/drift-orchestrator-cron.yaml |
GHA schedule → WP event: cron (04:00 UTC daily) |
Yes (vault) | Config drift check; no postgres service |
flag-drift-check.yml |
.woodpecker/flag-drift-check.yaml |
GHA schedule → WP event: cron (06:00 UTC daily) |
Yes (CF, console token) | Flag reconciliation check; no postgres |
heroku-admin.yml |
.woodpecker/heroku-admin.yaml |
GHA workflow_dispatch → WP event: manual |
Yes (Heroku key) | Operator admin tool; no postgres |
infra-ci-validate.yml |
.woodpecker/infra-ci-validate.yaml |
GHA pull_request + push → WP event: [pull_request,push] |
No | Terraform validate; no postgres |
launch-readiness-check.yml |
.woodpecker/launch-readiness-check.yaml |
GHA workflow_dispatch → WP event: manual |
Yes (multiple) | Manual launch gate; no postgres |
lint-cf-access-headers.yml |
.woodpecker/lint-cf-access-headers.yaml |
GHA pull_request → WP event: pull_request |
No | Static lint |
lint-cf-pages-deploy-uniqueness.yml |
.woodpecker/lint-cf-pages-deploy-uniqueness.yaml |
GHA pull_request → WP event: pull_request |
No | Static lint |
lint-cf-tokens.yml |
.woodpecker/lint-cf-tokens.yaml |
GHA pull_request → WP event: pull_request |
Yes (CF token check) | CF token validation lint |
lint-workflow-secret-names.yml |
.woodpecker/lint-workflow-secret-names.yaml |
GHA pull_request → WP event: pull_request |
No | Static lint; note: when GHA workflows are retired, this lint target changes to .woodpecker/*.yaml files |
migration-collision-check.yml |
.woodpecker/migration-collision-check.yaml |
GHA pull_request → WP event: pull_request |
No | Required status check; see §4 swap |
ops-mint-preview-invite.yml |
.woodpecker/ops-mint-preview-invite.yaml |
GHA workflow_dispatch → WP event: manual |
Yes (Velvet token) | Manual operator tool |
pii-scan.yml |
.woodpecker/pii-scan.yaml |
GHA pull_request → WP event: pull_request |
No | PII pattern scan |
postmark-delivery-monitor.yml |
.woodpecker/postmark-delivery-monitor.yaml |
GHA schedule → WP event: cron (08:45 UTC daily) |
Yes (Postmark token) | Delivery monitor; was a Phase 2 pilot candidate |
pr-preview.yml |
.woodpecker/pr-preview.yaml |
GHA pull_request → WP event: pull_request |
Yes (CF Pages token) | Path-aware CF Pages preview deploys; deployments: write GHA permission replaced by explicit gh + CF API calls with bot token |
queue-zero-dyno-monitor.yml |
.woodpecker/queue-zero-dyno-monitor.yaml |
GHA schedule → WP event: cron (every 30 min) |
Yes (Heroku key) | Was a Phase 2 pilot candidate |
reminders-second-factor-nightly.yml |
.woodpecker/reminders-second-factor-nightly.yaml |
GHA schedule → WP event: cron (09:00 UTC daily) |
Yes (Postmark) | Second-factor reminder emails; no postgres |
review-app-console.yml |
.woodpecker/review-app-console.yaml |
GHA pull_request → WP event: pull_request |
Yes (Heroku key) | Heroku review app lifecycle; PR open/close events |
sc-ident-6-smoke.yml |
.woodpecker/sc-ident-6-smoke.yaml |
GHA workflow_dispatch → WP event: manual |
Yes (bot App keys) | Bot identity smoke; create-github-app-token Action replaced by inline wpc_load_vault_secrets.py + gh call |
terraform-validate.yml |
.woodpecker/terraform-validate.yaml |
GHA pull_request + push → WP event: [pull_request,push] |
No | terraform validate; no postgres |
vcpkg-manifest-check.yml |
.woodpecker/vcpkg-manifest-check.yaml |
GHA pull_request → WP event: pull_request |
No | vcpkg lockfile lint |
Wave A total: 30 workflows + 2 Phase 2 pilot completions (alembic-version-cron, maxmind-asn-refresh)
Wave B — heavy CI, postgres service, remaining crons, e2e/ZAP
Entry criterion: Wave A 7-day soak + postgres:15 service container smoke green
on Amazon Linux 2023 Docker agent.
| GHA workflow file | WP target file | Trigger mapping | Postgres? | Notes |
|---|---|---|---|---|
account-merge-tombstone-cron.yml |
.woodpecker/account-merge-tombstone-cron.yaml |
event: cron (04:00 UTC daily) |
Via Heroku run | PORTED+RETIRED 2026-07-07 (#4068) |
audit-integrity-cron.yml |
.woodpecker/audit-integrity-cron.yaml |
event: cron (02:00 UTC daily + 03:30 UTC 1st) |
Via Heroku run | PORTED+RETIRED 2026-07-07 (#4067); two cron entries |
audit-reconciler-cron.yml |
.woodpecker/audit-reconciler-cron.yaml |
event: cron (03:30 UTC daily) |
Via Heroku run | PORTED+RETIRED 2026-07-07 (#4067) |
bcp-smoke-monthly.yml |
.woodpecker/bcp-smoke-monthly.yaml |
event: cron (1st of month, 06:00 UTC) |
Via Heroku run | |
billing-collector-cron.yml |
.woodpecker/billing-collector-cron.yaml |
event: manual only |
Via Heroku run | WP YAML written 2026-07-07 (#4068); cron NOT registered; GHA NOT retired — PAUSED pending #2159 |
billing-retention-cron.yml |
.woodpecker/billing-retention-cron.yaml |
event: cron (03:00 UTC daily) |
Via Heroku run | PORTED+RETIRED 2026-07-07 (#4068) |
ci-pr.yml (postgres step) |
.woodpecker/ci-pr.yaml (backend-tests-postgres step added) |
Part of Wave A WP file | Local service | Wave A ships the pipeline without the postgres step; Wave B adds services: postgres:15 block and the backend-tests-postgres step |
ci.yml (backend-tests-postgres) |
.woodpecker/ci-develop.yaml (backend-tests-postgres step added) |
Part of Wave A WP file | Local service | Same as above — Wave B adds the services: block |
e2e-smoke.yml |
.woodpecker/e2e-smoke.yaml |
event: cron (06:00 UTC daily) |
Via staging URL | Playwright E2E; staging URL; no local postgres |
freescout-backup.yml |
.woodpecker/freescout-backup.yaml |
event: cron (04:00 UTC daily) |
Via Heroku run | |
heroku-config-health-nightly.yml |
.woodpecker/heroku-config-health-nightly.yaml |
event: cron (05:00 UTC daily) |
Via Heroku run | PORTED+RETIRED 2026-07-07 (#4068) |
historical-bars-1min-warm-nightly.yml |
.woodpecker/historical-bars-1min-warm-nightly.yaml |
event: cron (05:30 UTC daily) |
Via Heroku run | Market data API + Heroku; no local postgres |
mbt-assignment-at-expiry-cron.yml |
.woodpecker/mbt-assignment-at-expiry-cron.yaml |
event: cron (weekly Mon 01:00 UTC) |
Via Heroku run | |
mbt-dividend-split-cron.yml |
.woodpecker/mbt-dividend-split-cron.yaml |
event: cron (weekly Sun 02:00 UTC) |
Via Heroku run | |
mbt-drift-daily.yml |
.woodpecker/mbt-drift-daily.yaml |
event: cron (04:30 UTC daily) |
Via Heroku run | |
mbt-drift-per-symbol-weekly.yml |
.woodpecker/mbt-drift-per-symbol-weekly.yaml |
event: cron (weekly Sat 03:00 UTC) |
Via Heroku run | |
mbt-resting-orders-cron.yml |
.woodpecker/mbt-resting-orders-cron.yaml |
event: cron (hourly) |
Via Heroku run | |
nightly-security-scan.yml |
.woodpecker/security-scan-nightly.yaml (expand existing) |
event: cron (08:07 UTC daily) — already registered |
Yes (partial) | Add raxx-ops-bot token mint, GH issue-filing (scan_file_issues.py), PR creation, Slack-on-failure to existing pilot pipeline |
queue-docker-smoke.yml |
.woodpecker/queue-docker-smoke.yaml |
event: push, branch: develop |
No | Queue C++ Docker build smoke; size:heavy label recommended (multi-stage build) |
security-zap.yml |
.woodpecker/security-zap.yaml |
event: cron (weekly) |
No | ZAP against staging URL; requires live staging network access |
tickets-e2e-smoke.yml |
.woodpecker/tickets-e2e-smoke.yaml |
event: cron (06:30 UTC daily) |
No | E2E against FreeScout staging |
trace-integrity-cron.yml |
.woodpecker/trace-integrity-cron.yaml |
event: cron (02:00 UTC Sun weekly) |
Via Heroku run | PORTED+RETIRED 2026-07-07 (#4067) |
Wave B total: 22 workflows (20 new + 2 postgres step additions to Wave A pipelines)
Wave C — deploy, release, gatekeeper pipelines
Entry criterion: Wave B 7-day parity soak; Console Ops Dispatch sub-card filed and in active development; branch-protection WP checks are sole required gate on develop.
Deploy pipelines are migrated staging-first within Wave C: each pipeline is
enabled for branch: release (staging) first, soaked for 5 days, then
branch: main (production) is enabled. The gatekeeper and promote-to-main
pipelines go last (after all staging deploys are proven).
| GHA workflow file | WP target file | Trigger mapping | Vault? | Notes |
|---|---|---|---|---|
deploy-antlers-cutover.yml |
.woodpecker/deploy-antlers-cutover.yaml |
event: manual |
Yes (CF token) | One-shot cutover; manual only |
deploy-antlers-next-prod.yml |
.woodpecker/deploy-antlers-next-prod.yaml |
event: push, branch: main |
Yes (CF Pages token) | Cloudflare Pages deploy via wrangler; NEXT_PUBLIC_* env vars injected at build |
deploy-antlers-next-staging.yml |
.woodpecker/deploy-antlers-next-staging.yaml |
event: push, branch: release |
Yes (CF Pages token) | |
deploy-console-shim.yml |
.woodpecker/deploy-console-shim.yaml |
event: push, branch: main |
Yes (Heroku key) | |
deploy-console.yml |
.woodpecker/deploy-console.yaml |
event: push, branch: [release,main] |
Yes (Heroku key) | notify-deploy-status → wpc_notify_deploy_status.py; check-deploy-freeze → wpc_check_deploy_freeze.sh |
deploy-customer-docs.yml |
.woodpecker/deploy-customer-docs.yaml |
event: push, branch: main |
Yes (CF token) | |
deploy-failure-streak-alert.yml |
.woodpecker/deploy-failure-streak-alert.yaml |
event: cron (every 30 min) |
Yes (Slack, GH token) | |
deploy-flag-docs.yml |
.woodpecker/deploy-flag-docs.yaml |
event: push, branch: main |
Yes (CF token) | |
deploy-getraxx.yml |
.woodpecker/deploy-getraxx.yaml |
event: push, branch: main |
Yes (CF Pages token) | Vite build + CF Pages deploy |
deploy-heroku.yml |
.woodpecker/deploy-heroku.yaml |
event: push, branch: [release,main] + event: manual |
Yes (Heroku key — prod key restricted to event:tag,manual) | Biggest deploy pipeline. Inline synthetic gate steps for staging (replaces synthetic-gate.yml workflow_call). notify-deploy-status → wpc_notify_deploy_status.py. check-deploy-freeze → wpc_check_deploy_freeze.sh. |
deploy-internal-docs.yml |
.woodpecker/deploy-internal-docs.yaml |
event: push, branch: main |
Yes (CF token) | |
deploy-mockups.yml |
.woodpecker/deploy-mockups.yaml |
event: push, branch: main |
Yes (CF Pages token) | |
deploy-queue-failure-monitor.yml |
.woodpecker/deploy-queue-failure-monitor.yaml |
event: cron + event: push, branch: main |
Yes | |
deploy-queue.yml |
.woodpecker/deploy-queue.yaml |
event: push, branch: [release,main] |
Yes (Heroku key) | |
deploy-status-page.yml |
.woodpecker/deploy-status-page.yaml |
event: push, branch: main |
Yes (CF Pages token) | |
deploy-status-worker.yml |
.woodpecker/deploy-status-worker.yaml |
event: push, branch: main |
Yes (CF Worker token) | |
deploy-support.yml |
.woodpecker/deploy-support.yaml |
event: push, branch: main |
Yes (CF token) | FreeScout deploy |
deploy-velvet.yml |
.woodpecker/deploy-velvet.yaml |
event: push, branch: [release,main] |
Yes (Heroku key) | |
deploy-worker-waf-log-shipper.yml |
.woodpecker/deploy-worker-waf-log-shipper.yaml |
event: push, branch: main |
Yes (CF Worker token) | |
freescout-apply.yml |
.woodpecker/freescout-apply.yaml |
event: manual |
Yes (FreeScout token) | Applies FreeScout config; manual only |
gatekeeper-develop-to-release.yml |
.woodpecker/gatekeeper-develop-to-release.yaml |
event: tag, tag: release-* |
Yes (raxx-ops-bot App key) | Highest-risk pipeline. See ADR-0135 §3 for full design. Port cut-release-candidate.yml in same wave. |
cut-release-candidate.yml |
.woodpecker/cut-release-candidate.yaml |
event: manual |
Yes (raxx-ops-bot App key) | Creates release-* tag on develop HEAD; fires gatekeeper |
promote-release-to-main.yml |
.woodpecker/promote-release-to-main.yaml |
event: tag, tag: v*.*.* |
Yes (raxx-ops-bot App key) | Highest-risk. Heavy scan suite + merge release→main + gh release create. See ADR-0135 §3 and §5. |
synthetic-gate.yml |
.woodpecker/synthetic-gate-cron.yaml (standalone cron only) |
event: cron (weekly) |
Yes (CF Access synthetic) | workflow_call uses replaced by inline steps in deploy-heroku.yaml; standalone cron becomes a separate WP pipeline |
terraform-email-delivery-stack.yml |
.woodpecker/terraform-email-delivery-stack.yaml |
event: [pull_request,push] |
Yes (AWS creds via vault) | Terraform apply for email delivery stack |
waf-synthetic-probe.yml |
.woodpecker/waf-synthetic-probe.yaml |
event: cron (hourly) |
Yes (CF, probe token) | Probes live WAF endpoints; depends on prod being live |
Wave C total: 26 workflows
Wave D — decommission (not a migration wave; no new WP pipelines)
All remaining GHA workflows are disabled and archived. No new .woodpecker/*.yaml
files are created in this wave.
| Action | Detail |
|---|---|
| Bulk disable all GHA workflows | gh workflow disable for each file; bulk script in Wave D sub-card D4 |
Retain .github/workflows/ 30 days |
Incident reference; do not delete |
| Archive after 30-day soak | git mv .github/workflows .github/workflows-retired |
| GHA spending limit → $20/month | iOS macOS buffer per ADR-0134 |
Build /onboard-ci skill |
scripts/skills/onboard-ci.sh; Woodpecker-native version (POST /api/repos to activate; org-secret inheritance; canary pipeline; see ADR-0134 §9 for sketch) |
| Close #728, update #726 | Ubicloud card superseded; billing posture updated |
Section 5 — Trigger mapping reference
Quick reference for translating GHA trigger syntax to Woodpecker v3 when: blocks:
| GHA trigger | WP equivalent |
|---|---|
on: push: branches: [develop] |
when: event: push, branch: develop |
on: push: branches: [release, main] |
when: event: push, branch: [release, main] |
on: push: tags: ['release-*'] |
when: event: tag, tag: release-* |
on: push: tags: ['v*.*.*'] |
when: event: tag, tag: v*.*.* |
on: pull_request: types: [opened, synchronize, reopened] |
when: event: pull_request |
on: schedule: cron: '7 8 * * *' |
WP cron registered via API + when: event: cron, cron: <name> |
on: workflow_dispatch |
when: event: manual |
on: workflow_call |
No equivalent — steps inlined in calling pipeline |
on: workflow_run |
No equivalent — use inline on_failure step or cron |
services: postgres:15 |
services: postgres: image: postgres:15 ... (same Docker Compose-style syntax in WP) |
uses: actions/checkout@v4 fetch-depth: 0 |
clone: - name: clone image: woodpecker-ci/plugin-git settings: depth: 0 |
uses: actions/setup-python@v5 |
Replace with image: python:3.11 on the step |
uses: actions/setup-node@v4 |
Replace with image: node:20-slim on the step |
uses: actions/cache@v4 |
WP has no native cache action; use WP Docker layer cache or a shared volume step |
${{ github.sha }} |
$CI_COMMIT_SHA |
${{ github.ref_name }} |
$CI_COMMIT_TAG (for tag events) or $CI_COMMIT_BRANCH |
${{ github.run_id }} |
$CI_BUILD_NUMBER |
${{ github.token }} |
Not available; mint raxx-ops-bot token via vault init step |
>> "$GITHUB_ENV" |
Same-step source pattern — WOODPECKER_ENV_FILE is NOT set in step context on WP v3.16.0 (confirmed build #6). Use wpc_load_vault_secrets.py + . /tmp/vault-env.sh && rm -f /tmp/vault-env.sh within the SAME step. See §1 of docs/architecture/woodpecker-wpc-step-usage.md. |
>> "$GITHUB_OUTPUT" |
Write to a file, then read in subsequent steps via commands: |
::error::message |
echo "message"; exit 1 (WP marks step as failed on non-zero exit) |
if: always() |
when: status: [success, failure] |
if: failure() |
when: status: failure |
if: success() |
when: status: success (WP default; can be omitted) |
concurrency: cancel-in-progress: true |
WP does not have a native concurrency group; use depends_on + pipeline-level when: to sequence manually |
Section 6 — Wave entry criteria and rollback stances
Wave A
Entry: Phase 2 complete (✓). Composite action scripts (wpc_*.py/wpc_*.sh)
merged. WP org-level secrets set.
Gate to declare A complete: 7-day soak; all 30 Wave A WP pipelines run successfully
at least twice; WP branch-protection checks added alongside GHA (PRs pass both).
Rollback: Disable WP pipelines in WP admin UI. GHA workflows remain active;
branch-protection GHA checks remain required. Zero blast radius.
Wave B
Entry: Wave A gate passed. postgres:15 service container smoke green on a
c6a.xlarge AL2023 agent (run once manually; confirm pg_isready passes before
enabling the step in ci-pr.yaml and ci-develop.yaml).
Gate to declare B complete: 7-day soak; 20+ successful backend-tests-postgres
WP runs; all remaining crons green twice. Branch protection swapped to WP-only
on develop.
Rollback: Re-enable GHA check names in branch protection (5-minute operation);
disable WP backend-postgres step via pipeline YAML PR.
Wave C
Entry: Wave B gate passed. Console Ops Dispatch sub-card (C-console) in active
development (does not need to be merged; just filed and understood). Operator has
confirmed prod deploy authorization design (WP secret event restriction) is
acceptable.
Sequencing within Wave C:
1. Enable staging-only deploys (branch: release) for all deploy pipelines.
2. 5-day staging soak: run 3+ full release-* tag → staging deploy cycles via WP.
3. Enable gatekeeper and promote-to-main pipelines.
4. Enable prod deploys (branch: main). Merge Console Ops Dispatch sub-card.
Gate to declare C complete: 2+ prod deploys via WP; no GHA fallback needed;
Console Ops Dispatch calls WP API successfully.
Rollback: Re-enable GHA deploy workflows by removing the if: false disable
flag (or via gh workflow enable). Each workflow is independently reversible in
< 5 minutes.
Wave D
Entry: Wave C 14-day prod soak. No deploy incidents requiring GHA fallback.
Work: Bulk disable GHA workflows; set GHA spending limit; build /onboard-ci.
Rollback: GHA workflows are disabled, not deleted, for 30 days. Re-enable via
gh workflow enable <file> if an emergency rollback is needed. After 30-day
archive, rollback requires a git revert of the archive commit — operationally
acceptable given the 30-day soak.
Section 7 — Branch protection API changes
develop branch (changes during Wave A + Wave B)
Wave A addition (add WP checks alongside existing GHA checks):
PATCH /repos/raxx-app/TradeMasterAPI/branches/develop/protection
{
"required_status_checks": {
"strict": true,
"checks": [
{"context": "PR Gates / Backend tests"},
{"context": "CI — develop / Backend tests"},
{"context": "ci/woodpecker/ci-pr/backend-tests-postgres"},
{"context": "ci/woodpecker/ci-pr/frontend-tests"},
{"context": "ci/woodpecker/ci-pr/sprint-readiness-gate"},
{"context": "ci/woodpecker/ci-pr/base-branch-lint"},
{"context": "ci/woodpecker/migration-collision-check/check"},
{"context": "ci/woodpecker/ci-develop/backend-tests-postgres"}
]
}
}
Wave B removal (remove GHA checks; keep only WP):
{
"required_status_checks": {
"strict": true,
"checks": [
{"context": "ci/woodpecker/ci-pr/backend-tests-postgres"},
{"context": "ci/woodpecker/ci-pr/frontend-tests"},
{"context": "ci/woodpecker/ci-pr/sprint-readiness-gate"},
{"context": "ci/woodpecker/ci-pr/base-branch-lint"},
{"context": "ci/woodpecker/migration-collision-check/check"},
{"context": "ci/woodpecker/ci-develop/backend-tests-postgres"}
]
}
}
Note: The exact WP check context names depend on the .woodpecker/*.yaml
pipeline filenames and step names written in Wave A. Wave A sub-card A7 audits
the actual check names reported by WP after the first successful run before
executing the branch protection API call. Do not hardcode these names before
verifying.
release and main branches
Existing required checks on release and main are likely gatekeeper-related
checks, not PR-CI checks (since merges are automated via bot). Audit in Wave C
sub-card C-bp before touching. Pattern is the same: add WP check names alongside
GHA during Wave C staging soak, swap to WP-only after prod cutover confirmed.