-
Notifications
You must be signed in to change notification settings - Fork 1
152 lines (141 loc) · 6.73 KB
/
Copy pathcd.yml
File metadata and controls
152 lines (141 loc) · 6.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# Continuous Deployment — OrangeCat → bitbaum (self-hosted Hetzner).
#
# Runs ONLY after the CI workflow succeeds on main, builds the standalone bundle
# off-box (the box OOMs on build), and ships it via the atomic-swap+rollback
# deploy verb (scripts/deploy-selfhost.sh). The deploy half the manual runbook
# used to do by hand — this closes the tested→live seam.
#
# DISABLED until secrets are configured: every deploy step is gated on
# `steps.guard.outputs.ok`, which is false unless SELFHOST_SSH_KEY exists. So
# merging this file is a safe no-op; CD activates the moment the key is added.
#
# Required repo secrets (Settings → Secrets and variables → Actions):
# SELFHOST_SSH_KEY private SSH key whose public half is in the box's
# authorized_keys for the OC_BOX user (default root). Treat
# as a deploy credential; rotate if leaked.
# SELFHOST_KNOWN_HOSTS output of `ssh-keyscan 167.233.22.31` (pins the host).
# NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEY /
# NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY real self-host values, baked at build.
# Optional repo variables (vars.*):
# OC_BOX (default root@167.233.22.31)
#
# Note: OrangeCat's build does not require live-DB access (no blocking SSG DB
# queries), so unlike fleetcrown/scripts/hetzner/deploy.sh this needs no tunnel.
name: CD
on:
workflow_run:
workflows: ['CI']
types: [completed]
branches: [main]
workflow_dispatch: {} # allow manual redeploy of current main
concurrency:
group: cd-selfhost
cancel-in-progress: false # never interrupt a deploy mid-swap
jobs:
deploy:
# Only on green CI (or a manual dispatch).
if: >-
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
timeout-minutes: 25
env:
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY }}
# OrangeCat's public donation addresses, baked into the client bundle for
# the /support founding-supporter page. Repo *variables* (not secrets) —
# these are public receiving addresses, meant to be shown. Unset → the
# page shows its graceful "opens shortly" state. (NEXT_PUBLIC_* must be set
# HERE at build time; the box's runtime .env can't reach the client bundle.)
NEXT_PUBLIC_LIGHTNING_ADDRESS: ${{ vars.NEXT_PUBLIC_LIGHTNING_ADDRESS }}
NEXT_PUBLIC_BITCOIN_ADDRESS: ${{ vars.NEXT_PUBLIC_BITCOIN_ADDRESS }}
# Flips the Cat Credits UI from "Activating" to "Live" (build-time, client
# bundle). Set the repo variable to true only once PLATFORM_NWC_URI exists
# in the box's runtime .env — the UI must never claim Live before the
# server can actually receive. Server-side receive is gated independently
# on PLATFORM_NWC_URI (runtime), so this flag is display-only.
NEXT_PUBLIC_CAT_CREDITS_LIVE: ${{ vars.NEXT_PUBLIC_CAT_CREDITS_LIVE }}
# Voice input on create forms and onboarding. This was missing here for
# its whole life, which meant the flag could never be true in production:
# NEXT_PUBLIC_* is compiled into the client bundle, so setting it in the
# box's runtime .env does nothing. The mic on every create form was
# unreachable dead code — off by omission, not by decision.
NEXT_PUBLIC_FEATURE_VOICE_INPUT: ${{ vars.NEXT_PUBLIC_FEATURE_VOICE_INPUT }}
# FleetCrown feedback widget token — must match ci.yml's build env so a
# cd-side rebuild bakes the same embed into prerendered pages. Public by
# design (ships in page source): repo variable, not a secret.
FLEETCROWN_FEEDBACK_TOKEN: ${{ vars.FLEETCROWN_FEEDBACK_TOKEN }}
OC_BOX: ${{ vars.OC_BOX || 'root@167.233.22.31' }}
steps:
- name: Guard — is the deploy key configured?
id: guard
env:
KEY: ${{ secrets.SELFHOST_SSH_KEY }}
run: |
if [ -n "$KEY" ]; then
echo "ok=true" >> "$GITHUB_OUTPUT"
else
echo "ok=false" >> "$GITHUB_OUTPUT"
echo "::notice::SELFHOST_SSH_KEY not set — CD is dormant. Add it to enable deploys."
fi
- name: Checkout
if: steps.guard.outputs.ok == 'true'
uses: actions/checkout@v7
- name: Setup Node.js
if: steps.guard.outputs.ok == 'true'
uses: actions/setup-node@v7
with:
node-version: 24
cache: 'npm'
- name: Install dependencies
if: steps.guard.outputs.ok == 'true'
run: npm ci
- name: Download standalone artifact from the triggering CI run
# Ship the EXACT artifact CI built + tested (tested == shipped), and skip
# the rebuild. Best-effort: if the download fails — or this is a manual
# dispatch with no CI run behind it — the next step falls back to building,
# so a broken artifact path can never break deploys (worst case = today).
if: steps.guard.outputs.ok == 'true' && github.event_name == 'workflow_run'
continue-on-error: true
uses: actions/download-artifact@v8
with:
name: standalone-${{ github.event.workflow_run.head_sha }}
path: .next/standalone
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Build standalone if no artifact (fallback / manual dispatch)
if: steps.guard.outputs.ok == 'true'
env:
NODE_ENV: production
SELF_HOST: '1'
run: |
if [ -f .next/standalone/server.js ]; then
echo "Using the CI-built standalone artifact — skipping rebuild."
else
echo "No artifact (manual dispatch or download failed) — building standalone."
npm run build
fi
- name: Configure SSH
if: steps.guard.outputs.ok == 'true'
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SELFHOST_SSH_KEY }}" > ~/.ssh/id_deploy
chmod 600 ~/.ssh/id_deploy
if [ -n "${{ secrets.SELFHOST_KNOWN_HOSTS }}" ]; then
echo "${{ secrets.SELFHOST_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
else
ssh-keyscan -H 167.233.22.31 >> ~/.ssh/known_hosts 2>/dev/null
fi
cat > ~/.ssh/config <<'EOF'
Host bitbaum
HostName 167.233.22.31
IdentityFile ~/.ssh/id_deploy
IdentitiesOnly yes
EOF
- name: Deploy (atomic swap + rollback)
if: steps.guard.outputs.ok == 'true'
run: |
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_deploy
bash scripts/deploy-selfhost.sh --no-build