Repository navigation
211 lines (186 loc) · 8.33 KB
/
Copy pathdeploy.yml
File metadata and controls
211 lines (186 loc) · 8.33 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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
name: deploy
# Deploys the legacy Worker and the data site (site, OG Worker, sync Workflow).
#
# Each service is split in two:
# - build runs repository code (bun install, cf build / bun script/build.ts) with
# no environment, no secrets and no OIDC token, and uploads the resolved Build
# Output with a SHA256SUMS whose digest it reports.
# - deploy runs in the dev|production environment and mints a short-lived
# Cloudflare token from the token issuer. It checks out only .github/release/,
# verifies the artifact against the digest the build job reported, installs
# the cf CLI pinned in .github/release/cf, and runs only
# .github/release/deploy-legacy.sh or deploy-data.sh. Those treat the artifact
# as data and refuse anything but the pinned targets in
# .github/release/targets/. That is what makes an account-wide token safe: the
# data sync Workflow PUT has no per-Worker permission, so only Dax-reviewed
# .github code ever holds a token that can write another Worker.
on:
push:
branches:
- dev
- production
workflow_dispatch:
concurrency: ${{ github.workflow }}-${{ github.ref }}
permissions:
contents: read
jobs:
legacy-build:
if: github.repository == 'anomalyco/opencode' && (github.ref_name == 'dev' || github.ref_name == 'production')
runs-on: blacksmith-4vcpu-ubuntu-2404
outputs:
digest: ${{ steps.upload.outputs.digest }}
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
ref: ${{ github.sha }}
persist-credentials: false
- uses: ./.github/actions/setup-bun
- name: Build
working-directory: services/legacy
run: ./node_modules/.bin/cf build --mode ${{ github.ref_name }}
- id: upload
uses: ./.github/release/upload
with:
name: legacy-${{ github.ref_name }}
path: services/legacy/.cloudflare/output
retention-days: 7
include-hidden-files: true
legacy-deploy:
needs: legacy-build
if: github.repository == 'anomalyco/opencode' && (github.ref_name == 'dev' || github.ref_name == 'production')
runs-on: blacksmith-4vcpu-ubuntu-2404
environment: ${{ github.ref_name }}
permissions:
contents: read
id-token: write
steps:
- name: Check out the deploy scripts
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
ref: ${{ github.sha }}
sparse-checkout: /.github/release/
sparse-checkout-cone-mode: false
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
- name: Install the pinned cf CLI
working-directory: .github/release/cf
run: npm ci --ignore-scripts --no-audit --no-fund
- name: Download
uses: ./.github/release/download
with:
pattern: legacy-${{ github.ref_name }}
require-digests: true
digests: legacy-${{ github.ref_name }}=${{ needs.legacy-build.outputs.digest }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0
with:
role-to-assume: arn:aws:iam::604439173067:role/github/opencode-${{ github.ref_name }}
role-session-name: opencode-${{ github.run_id }}
aws-region: us-east-1
# A 15-minute token for this stage, minted by the token issuer (anomalyco/secrets) from the role above.
# It is a step output, so only the Deploy step gets it.
- name: Cloudflare token
id: cloudflare-token
run: bash .github/release/cloudflare-token.sh "$GITHUB_REF_NAME"
env:
CLOUDFLARE_TOKEN_URL: ${{ vars.CLOUDFLARE_TOKEN_URL }}
# The GitHub App secrets are read here, so only this step ever has them. They reach cf through a file in the
# runner's temp directory, never argv, and the file is removed when the step ends.
- name: Deploy
env:
STAGE: ${{ github.ref_name }}
CLOUDFLARE_API_TOKEN: ${{ steps.cloudflare-token.outputs.token }}
# An explicit bash runs with pipefail, so a failed secret read fails the step.
shell: bash
run: |
if [[ "$STAGE" == dev ]]; then
exec bash .github/release/deploy-legacy.sh dev "$RUNNER_TEMP/in/legacy-dev"
fi
umask 077
secrets="$RUNNER_TEMP/legacy-secrets.json"
trap 'rm -f "$secrets"' EXIT
for name in GITHUB_APP_ID GITHUB_APP_PRIVATE_KEY; do
aws secretsmanager get-secret-value --secret-id "opencode/production/$name" --output json |
jq --arg name "$name" '{($name): .SecretString}'
done | jq -s add > "$secrets"
bash .github/release/deploy-legacy.sh "$STAGE" "$RUNNER_TEMP/in/legacy-$STAGE" "$secrets"
data-build:
if: github.repository == 'anomalyco/opencode' && (github.ref_name == 'dev' || github.ref_name == 'production')
runs-on: blacksmith-4vcpu-ubuntu-2404
outputs:
digest: ${{ steps.upload.outputs.digest }}
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
ref: ${{ github.sha }}
persist-credentials: false
- uses: ./.github/actions/setup-bun
- name: Build
working-directory: services/data
run: bun script/build.ts --mode ${{ github.ref_name }}
- id: upload
uses: ./.github/release/upload
with:
name: data-${{ github.ref_name }}
path: services/data/.cloudflare/output
retention-days: 7
include-hidden-files: true
# The /data site, its OG image Worker and the sync Workflow (services/data).
data-deploy:
needs: data-build
if: github.repository == 'anomalyco/opencode' && (github.ref_name == 'dev' || github.ref_name == 'production')
runs-on: blacksmith-4vcpu-ubuntu-2404
environment: ${{ github.ref_name }}
permissions:
contents: read
id-token: write
steps:
- name: Check out the deploy scripts
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
ref: ${{ github.sha }}
sparse-checkout: /.github/release/
sparse-checkout-cone-mode: false
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
- name: Install the pinned cf CLI
working-directory: .github/release/cf
run: npm ci --ignore-scripts --no-audit --no-fund
- name: Download
uses: ./.github/release/download
with:
pattern: data-${{ github.ref_name }}
require-digests: true
digests: data-${{ github.ref_name }}=${{ needs.data-build.outputs.digest }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0
with:
role-to-assume: arn:aws:iam::604439173067:role/github/opencode-${{ github.ref_name }}
role-session-name: opencode-${{ github.run_id }}
aws-region: us-east-1
- name: Cloudflare token
id: cloudflare-token
run: bash .github/release/cloudflare-token.sh "$GITHUB_REF_NAME"
env:
CLOUDFLARE_TOKEN_URL: ${{ vars.CLOUDFLARE_TOKEN_URL }}
# The Workers' secrets are read here, so only this step ever has them. They reach cf through files in the
# runner's temp directory, never argv, and are removed when the step ends.
- name: Deploy
env:
STAGE: ${{ github.ref_name }}
CLOUDFLARE_API_TOKEN: ${{ steps.cloudflare-token.outputs.token }}
# An explicit bash runs with pipefail, so a failed secret read fails the step.
shell: bash
run: |
umask 077
secrets="$RUNNER_TEMP/data-secrets.json"
trap 'rm -f "$secrets" "$secrets".*' EXIT
for name in DATA_DATABASE_HOST DATA_DATABASE_USERNAME DATA_DATABASE_PASSWORD R2_SQL_AUTH_TOKEN DATA_HIDDEN_MODELS; do
aws secretsmanager get-secret-value --secret-id "opencode/$STAGE/$name" --output json |
jq --arg name "$name" '{($name): .SecretString}'
done | jq -s add > "$secrets"
bash .github/release/deploy-data.sh "$STAGE" "$RUNNER_TEMP/in/data-$STAGE" "$secrets"