@decocms/start 2.30.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -58,9 +58,10 @@ export default createDecoWorkerEntry(serverEntry, {
58
58
  ```
59
59
 
60
60
  The `main` field is set centrally so a future migration of the entry path
61
- applies to every site at once (single PR to the template). If you ever need to
62
- override `main` for a single site, add it under `deploy/sites/<repo>.jsonc` —
63
- never to a per-site `wrangler.jsonc` (sites don't commit one; see D6).
61
+ applies to every site at once (single PR to the template). There is no
62
+ per-site override file (D6.2 Pure C); if a single site truly needs a different
63
+ entry path, change the template (and accept that all sites get it) or add a
64
+ substitution token like `$WORKER_ENTRY_PATH` and feed it from a per-site env.
64
65
 
65
66
  This ensures admin route interception AND edge caching survive the build because they're in the Worker's own fetch handler, outside of TanStack's build pipeline.
66
67
 
@@ -211,22 +212,26 @@ Or in project `.npmrc` with an env var (for CI):
211
212
  **Tradeoff with `github:` syntax**: No semver resolution — `npm update` is meaningless. Pin to a tag for stability: `github:decocms/deco-start#v0.14.2`. Without a tag, you get HEAD of the default branch.
212
213
 
213
214
 
214
- ## 46. Central Deploy / Wrangler Config (D6)
215
+ ## 46. Central Deploy / Wrangler Config (D6.2)
215
216
 
216
- **Severity**: HIGH — site repos must NOT commit `wrangler.jsonc` or per-site deploy logic. Doing so reintroduces drift.
217
+ **Severity**: HIGH — site repos must NOT commit `wrangler.jsonc`, must NOT hold
218
+ Cloudflare credentials, and must NOT have per-site deploy logic. Doing so
219
+ reintroduces drift and breaks the trust model.
217
220
 
218
- Per [D6](../../../../.cursor/rules/migration-tooling-policy.mdc), all
221
+ Per [D6.2](../../../../.cursor/rules/migration-tooling-policy.mdc), all
219
222
  storefronts deploy via reusable workflows shipped from
220
- `decocms/deco-start/.github/workflows/{deploy,preview,sync-secrets,regen-blocks}.yml@v2`.
221
- The canonical `wrangler.jsonc` lives at
222
- `decocms/deco-start/deploy/wrangler-template.jsonc`; per-site overrides live at
223
- `decocms/deco-start/deploy/sites/<repo-name>.jsonc`. The two are deep-merged at
224
- deploy time and written to a generated `wrangler.jsonc` in the runner; site
225
- repos gitignore the file.
223
+ `decocms/deco-start/.github/workflows/{deploy,preview,sync-secrets,regen-blocks}.yml@v3`.
224
+ There is no per-site registry: worker name == storefront repo basename by
225
+ convention. The canonical `wrangler.jsonc` lives at
226
+ `decocms/deco-start/deploy/wrangler-template.jsonc`; the build script
227
+ substitutes `$WORKER_NAME` / `$WORKER_UNDERSCORE` tokens at deploy time and
228
+ writes a generated `wrangler.jsonc` in the runner. Site repos gitignore the
229
+ file.
226
230
 
227
231
  ### What goes in the site repo
228
232
 
229
- Four ~5-line caller workflow stubs and nothing else:
233
+ Four caller workflow stubs that mint a `decocms-deployer` GitHub App
234
+ installation token and call `gh workflow run` on `decocms/deco-start@v3`:
230
235
 
231
236
  ```yaml
232
237
  # .github/workflows/deploy.yml
@@ -235,31 +240,48 @@ on:
235
240
  push:
236
241
  branches: [main]
237
242
  permissions:
238
- contents: write
243
+ contents: read
239
244
  jobs:
240
- deploy:
241
- uses: decocms/deco-start/.github/workflows/deploy.yml@v2
242
- secrets: inherit
245
+ trigger:
246
+ runs-on: ubuntu-latest
247
+ steps:
248
+ - uses: actions/create-github-app-token@v1
249
+ id: app-token
250
+ with:
251
+ app-id: ${{ secrets.DECOCMS_DEPLOYER_APP_ID }}
252
+ private-key: ${{ secrets.DECOCMS_DEPLOYER_APP_PRIVATE_KEY }}
253
+ owner: decocms
254
+ repositories: deco-start
255
+ - env:
256
+ GH_TOKEN: ${{ steps.app-token.outputs.token }}
257
+ run: |
258
+ gh workflow run deploy.yml \
259
+ --repo decocms/deco-start \
260
+ --ref v3 \
261
+ -f site_owner=${GITHUB_REPOSITORY%%/*} \
262
+ -f site_name=${GITHUB_REPOSITORY##*/}
243
263
  ```
244
264
 
245
265
  (Plus equivalent `preview.yml`, `regen-blocks.yml`, `sync-secrets.yml` —
246
266
  see `scripts/migrate/templates/github-workflows.ts` for the canonical text.)
247
- The migration script generates these for new sites; the same stubs are
248
- hand-applied to existing sites.
249
-
250
- ### What goes in `decocms/deco-start/deploy/sites/<repo>.jsonc`
251
-
252
- The minimum:
253
-
254
- ```jsonc
255
- {
256
- "worker_name": "<repo-name>"
257
- }
258
- ```
259
-
260
- Plus optional `routes`, `kv_namespaces`, `analytics_engine_datasets`,
261
- `version_metadata` for the few sites that need them. Adding a new site is a
262
- PR to deco-start, not a change to the site repo.
267
+ The migration script generates these for new sites.
268
+
269
+ ### App + secrets setup (one-time, per org)
270
+
271
+ 1. Create a `decocms-deployer` GitHub App with permissions
272
+ `Actions: Write`, `Contents: Read`, `Pull requests: Write` (the last
273
+ only needed if you want preview URLs commented on PRs),
274
+ `Metadata: Read`. Install it on `decocms/deco-start` and on each
275
+ storefront repo (or whole-org install on `deco-sites`).
276
+ 2. Store the App ID and private key as `deco-sites` org-level secrets
277
+ `DECOCMS_DEPLOYER_APP_ID` and `DECOCMS_DEPLOYER_APP_PRIVATE_KEY` so every
278
+ storefront workflow can mint installation tokens without per-repo setup.
279
+ 3. Store `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` as plain repo
280
+ secrets in `decocms/deco-start` (NOT in any storefront).
281
+ 4. For each storefront that has runtime secrets: create a GitHub Environment
282
+ in `decocms/deco-start` named `<storefront-repo-basename>-secrets`, add
283
+ the `SECRET_*` values there, and configure protection rules to grant the
284
+ site team self-service access to that environment only.
263
285
 
264
286
  ### Local dev
265
287
 
@@ -277,16 +299,31 @@ Site repos add three package.json hooks so vite picks up the generated
277
299
  ```
278
300
 
279
301
  `deco-wrangler` is a `bin` shipped from `@decocms/start` that materializes the
280
- canonical config from the central registry, then either exits (`gen` mode) or
281
- execs the real `wrangler` with that config in cwd.
302
+ canonical config from the central template (worker name inferred from git
303
+ remote / package.json), then either exits (`gen` mode) or execs the real
304
+ `wrangler` with that config in cwd.
282
305
 
283
306
  ### Trust model
284
307
 
285
- - The central workflow ignores all caller `inputs:` for site identity.
286
- - Site name is derived from `${{ github.repository }}` (set by GitHub,
287
- untamperable by user code) and looked up in `deploy/sites/<repo>.jsonc`.
288
- - A customer cannot misroute their deploy onto another site's worker
289
- because they can't write to `decocms/deco-start` (CODEOWNERS-protected).
308
+ - **Authorization gate**: the deploy can only start if the
309
+ `decocms-deployer` App is installed on the target storefront repo. The
310
+ central workflow's App-token mint step fails with a clear error otherwise.
311
+ - **Worker naming is convention-based and not customer-controlled.** A
312
+ customer with push access to their own storefront cannot rename the worker
313
+ their deploy lands on (the central workflow uses `inputs.site_name` as the
314
+ worker name; modifying their stub to pass a different `site_name` would
315
+ also require the App to be installed on that other repo).
316
+ - **Cloudflare credentials never leave `decocms/deco-start`.** The central
317
+ workflow runs in deco-start's context, so the env-var resolves natively
318
+ from repo secrets.
319
+ - **Force-rollback is impossible for production.** The central deploy
320
+ workflow ignores any caller-supplied sha and always resolves the
321
+ storefront's current default-branch HEAD itself.
322
+ - **Per-site runtime secrets** (`SECRET_*`) live in deco-start environments,
323
+ not storefront repos. The storefront caller stub for `sync-secrets.yml`
324
+ triggers a workflow that binds to the matching env and runs
325
+ `wrangler secret put`. The storefront repo holds zero secrets beyond the
326
+ `decocms-deployer` App credentials.
290
327
 
291
328
  ### Common mistakes (do not do these)
292
329
 
@@ -295,12 +332,17 @@ execs the real `wrangler` with that config in cwd.
295
332
  - **Adding a site-local `deploy.yml` step** (e.g. cache purge after deploy).
296
333
  Add it to `deco-start/.github/workflows/deploy.yml` instead so every site
297
334
  picks it up at once.
335
+ - **Adding `CLOUDFLARE_*` to a storefront repo's secrets.** They never
336
+ belong there. The central workflow runs in deco-start's context.
337
+ - **Adding `SECRET_*` to a storefront repo's secrets.** They live in the
338
+ matching `<site_name>-secrets` environment in deco-start.
298
339
  - **Hard-coding `account_id` in a site's wrangler config.** It comes from
299
- `CLOUDFLARE_ACCOUNT_ID` (org-level GitHub secret in CI; `wrangler login`
300
- locally). Removing it from JSON is the one-way protection against
301
- accidentally deploying to the wrong account.
302
- - **Setting `worker_name` to anything other than the repo name** without
303
- a strong reason. The 1:1 binding makes audit (and incident response)
304
- trivial. Exceptions today: `casaevideo-storefront` -> `casaevideo-tanstack`
305
- and `miess-01-tanstack` -> `miess-tanstack` (both for historical
306
- Cloudflare worker names that predate the repo).
340
+ `CLOUDFLARE_ACCOUNT_ID` (in CI; `wrangler login` locally) — keeping
341
+ it out of JSON is the one-way protection against accidentally deploying
342
+ to the wrong account.
343
+ - **Trying to override the worker name** for one site. There is no
344
+ per-site override mechanism in D6.2. If the worker MUST be named
345
+ differently from the repo, the right answer is either to rename the
346
+ repo to match (cleanest) or to do a CF-side migration (deploy a new
347
+ worker with the repo-name and re-attach routes). This trade-off was
348
+ taken intentionally in exchange for the registry-free architecture.
@@ -76,24 +76,51 @@ Failure modes get documented in skills, not encoded as escape hatches.
76
76
  **Agent behavior**: when a migration goes sideways, propose deletion +
77
77
  re-run, not in-place repair. Add the failure mode to the skill.
78
78
 
79
- ### D6 — Deploy / preview / secrets pipelines: centralize in `deco-start` (signed off 2026-05-07)
79
+ ### D6.2App-mediated dispatch + no per-site registry (signed off 2026-05-07; supersedes D6 + D6.1)
80
80
  All storefronts deploy via reusable workflows under
81
- `decocms/deco-start/.github/workflows/{deploy,preview,sync-secrets,regen-blocks}.yml@v2`.
82
- Per-site overrides live in [`deploy/sites/<repo>.jsonc`](../../deploy/) and
83
- are deep-merged on top of [`deploy/wrangler-template.jsonc`](../../deploy/wrangler-template.jsonc)
84
- at deploy time. **Customer repos do not commit `wrangler.jsonc`** it is
85
- generated locally by `deco-wrangler gen` (a `bin` shipped from
86
- `@decocms/start`) and gitignored. The repo→worker binding is the trust
87
- boundary: the central workflow ignores caller `inputs:` for identity and
88
- derives the site name from `${{ github.repository }}`. `deploy/**` is
81
+ `decocms/deco-start/.github/workflows/{deploy,preview,sync-secrets,regen-blocks}.yml@v3`.
82
+ Storefront caller stubs mint a short-lived **`decocms-deployer` GitHub App**
83
+ installation token (App ID + private key live as `deco-sites` org-level
84
+ secrets) and call `gh workflow run deploy.yml --repo decocms/deco-start --ref v3
85
+ -f site_owner=… -f site_name=…`. The central workflow runs in
86
+ **`decocms/deco-start`'s context**, so `CLOUDFLARE_API_TOKEN` and
87
+ `CLOUDFLARE_ACCOUNT_ID` are ordinary repo secrets in `decocms/deco-start`
88
+ and never leave it.
89
+
90
+ There is **no per-site registry under `deploy/sites/`**. Worker name == storefront
91
+ repo basename by convention. Per-worker derived fields use `$WORKER_NAME` /
92
+ `$WORKER_UNDERSCORE` substitution tokens in
93
+ [`deploy/wrangler-template.jsonc`](../../deploy/wrangler-template.jsonc).
94
+ The deploy authorization gate is the App being installed on the storefront
95
+ repo — if it isn't, the App-token mint inside the central workflow fails and
96
+ the deploy never starts. **Customer repos do not commit `wrangler.jsonc`** —
97
+ it is generated locally by `deco-wrangler gen` (a `bin` shipped from
98
+ `@decocms/start`) and gitignored.
99
+
100
+ Production deploys are **force-rollback proof**: the central workflow ignores
101
+ any caller-supplied `site_sha` and resolves the storefront's current default
102
+ branch HEAD itself. The worst a compromised storefront can do across tenants
103
+ is trigger a no-op redeploy of another storefront's current main.
104
+
105
+ `SECRET_*` runtime secrets live in **`decocms/deco-start`** as well, in
106
+ per-storefront GitHub Environments named `<site_name>-secrets`. `sync-secrets.yml`
107
+ binds to the matching environment and runs `wrangler secret put`. Site teams
108
+ get edit/approve permission on their own environment via Environment
109
+ protection rules. **The storefront repo holds zero secrets** beyond the
110
+ App credentials (which only grant the ability to trigger workflows on
111
+ `decocms/deco-start`).
112
+
113
+ `deploy/`, `scripts/deploy/`, and the central workflow files are
89
114
  CODEOWNERS-protected.
90
115
 
91
116
  **Agent behavior**: when adding or migrating a site, do **not** generate a
92
- per-site `wrangler.jsonc` or per-site `deploy.yml` / `preview.yml` /
93
- `sync-secrets.yml` / `regen-blocks.yml`. The site repo gets the four
94
- ~5-line caller stubs only. Per-site config goes in a PR to
95
- `decocms/deco-start` adding `deploy/sites/<repo>.jsonc`. Do not commit
96
- `wrangler.jsonc` or any wrangler config to a site repo.
117
+ per-site `wrangler.jsonc`, do **not** generate a `deploy/sites/<repo>.jsonc`
118
+ file (that whole directory was removed in D6.2), and do **not** add
119
+ `CLOUDFLARE_*` or `SECRET_*` to a storefront repo's secrets. The site repo
120
+ gets four ~15-line caller stubs that mint a `decocms-deployer` App token and
121
+ fire `workflow_dispatch` at `decocms/deco-start@v3`; the App ID + private key
122
+ live as `deco-sites` org-level secrets `DECOCMS_DEPLOYER_APP_ID` and
123
+ `DECOCMS_DEPLOYER_APP_PRIVATE_KEY`.
97
124
 
98
125
  ## Priority order
99
126
 
@@ -1,115 +1,141 @@
1
1
  name: deploy (central)
2
2
 
3
- # Reusable workflow that drives `wrangler deploy` for any storefront repo
4
- # registered under `deploy/sites/<repo-name>.jsonc`.
3
+ # Reusable workflow that drives `wrangler deploy` for any storefront repo.
4
+ # Worker name is the storefront repo basename by convention; there is no
5
+ # per-site registry. The deploy is gated by the `decocms-deployer` GitHub App
6
+ # being installed on the target storefront repo -- the App-token mint fails
7
+ # (and the deploy never starts) if the App isn't installed there.
5
8
  #
6
- # Site identity (worker name, KV bindings, routes, ...) is derived ONLY from
7
- # `${{ github.repository }}` and the registry checked in to deco-start. The
8
- # caller cannot pass an `inputs:` block to override the worker name -- this is
9
- # the trust boundary that prevents one site's commits from deploying on top of
10
- # another site's worker.
9
+ # v3 architecture (D6.2): triggered via `workflow_dispatch` from the storefront,
10
+ # authenticated as the `decocms-deployer` GitHub App. The deploy runs IN THIS
11
+ # REPO'S CONTEXT, so `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_ACCOUNT_ID` resolve
12
+ # from this repo's plain repo secrets and never leave decocms/deco-start.
11
13
  #
12
- # Caller usage (in customer repo, `.github/workflows/deploy.yml`):
14
+ # Caller usage (in the storefront repo, `.github/workflows/deploy.yml`):
13
15
  #
14
16
  # on:
15
17
  # push:
16
18
  # branches: [main]
17
19
  # permissions:
18
- # contents: write
20
+ # contents: read
19
21
  # jobs:
20
- # deploy:
21
- # uses: decocms/deco-start/.github/workflows/deploy.yml@v2
22
- # secrets: inherit
22
+ # trigger:
23
+ # runs-on: ubuntu-latest
24
+ # steps:
25
+ # - uses: actions/create-github-app-token@v1
26
+ # id: app-token
27
+ # with:
28
+ # app-id: ${{ secrets.DECOCMS_DEPLOYER_APP_ID }}
29
+ # private-key: ${{ secrets.DECOCMS_DEPLOYER_APP_PRIVATE_KEY }}
30
+ # owner: decocms
31
+ # repositories: deco-start
32
+ # - env:
33
+ # GH_TOKEN: ${{ steps.app-token.outputs.token }}
34
+ # run: |
35
+ # gh workflow run deploy.yml \
36
+ # --repo decocms/deco-start \
37
+ # --ref v3 \
38
+ # -f site_owner=${GITHUB_REPOSITORY%%/*} \
39
+ # -f site_name=${GITHUB_REPOSITORY##*/}
23
40
 
24
41
  on:
25
- workflow_call:
26
- secrets:
27
- CLOUDFLARE_API_TOKEN:
28
- required: true
29
- CLOUDFLARE_ACCOUNT_ID:
42
+ workflow_dispatch:
43
+ inputs:
44
+ site_owner:
45
+ description: "GitHub org of the storefront (e.g. deco-sites). Defaults to deco-sites."
46
+ type: string
47
+ required: false
48
+ default: deco-sites
49
+ site_name:
50
+ description: "Storefront repo basename. Becomes the Cloudflare worker name."
51
+ type: string
30
52
  required: true
31
53
 
32
54
  permissions:
33
- contents: write
55
+ contents: read
34
56
 
35
57
  concurrency:
36
- group: deploy-${{ github.repository }}
58
+ group: deploy-${{ inputs.site_owner }}-${{ inputs.site_name }}
37
59
  cancel-in-progress: false
38
60
 
39
61
  jobs:
40
62
  deploy:
41
63
  runs-on: ubuntu-latest
42
64
  steps:
43
- - name: Checkout caller repo
65
+ - name: Checkout deco-start (template + scripts)
44
66
  uses: actions/checkout@v4
45
67
 
46
- - name: Resolve deco-start ref + site identity
47
- id: meta
68
+ - name: Mint App token for storefront checkout
69
+ id: app-token
70
+ uses: actions/create-github-app-token@v1
71
+ with:
72
+ app-id: ${{ secrets.DECOCMS_DEPLOYER_APP_ID }}
73
+ private-key: ${{ secrets.DECOCMS_DEPLOYER_APP_PRIVATE_KEY }}
74
+ owner: ${{ inputs.site_owner }}
75
+ repositories: ${{ inputs.site_name }}
76
+
77
+ # SECURITY: production deploys IGNORE any caller-supplied sha. The deploy
78
+ # always targets the storefront's CURRENT default-branch HEAD. This means
79
+ # an attacker with push to repo A who triggers a deploy of repo B can
80
+ # only force a no-op redeploy of B's current main -- they cannot select
81
+ # an arbitrary historical commit (no force-rollback attack).
82
+ - name: Resolve target sha (storefront default branch HEAD)
83
+ id: target
84
+ env:
85
+ GH_TOKEN: ${{ steps.app-token.outputs.token }}
86
+ SITE_REPO: ${{ inputs.site_owner }}/${{ inputs.site_name }}
48
87
  run: |
49
- # github.workflow_ref looks like
50
- # decocms/deco-start/.github/workflows/deploy.yml@refs/tags/v1
51
- # or
52
- # decocms/deco-start/.github/workflows/deploy.yml@refs/heads/main
53
- WF_REF="${{ github.workflow_ref }}"
54
- REF="${WF_REF##*@}"
55
- REF="${REF#refs/tags/}"
56
- REF="${REF#refs/heads/}"
57
- echo "deco_start_ref=$REF" >> "$GITHUB_OUTPUT"
58
- echo "site_name=${GITHUB_REPOSITORY#*/}" >> "$GITHUB_OUTPUT"
88
+ set -euo pipefail
89
+ DEFAULT_BRANCH=$(gh api "repos/$SITE_REPO" --jq .default_branch)
90
+ SHA=$(gh api "repos/$SITE_REPO/branches/$DEFAULT_BRANCH" --jq .commit.sha)
91
+ echo "ref=$DEFAULT_BRANCH" >> "$GITHUB_OUTPUT"
92
+ echo "sha=$SHA" >> "$GITHUB_OUTPUT"
93
+ echo "::notice::Deploying $SITE_REPO @ $DEFAULT_BRANCH ($SHA)"
59
94
 
60
- - name: Checkout deco-start registry at the same ref
95
+ - name: Checkout storefront at default-branch HEAD
61
96
  uses: actions/checkout@v4
62
97
  with:
63
- repository: decocms/deco-start
64
- ref: ${{ steps.meta.outputs.deco_start_ref }}
65
- path: .deco-start
98
+ repository: ${{ inputs.site_owner }}/${{ inputs.site_name }}
99
+ ref: ${{ steps.target.outputs.sha }}
100
+ token: ${{ steps.app-token.outputs.token }}
101
+ path: site
102
+ fetch-depth: 1
66
103
 
67
104
  - uses: actions/setup-node@v4
68
105
  with:
69
106
  node-version: 22
70
107
 
71
- - name: Generate lockfile if missing
72
- if: hashFiles('package-lock.json') == ''
73
- run: npm install --package-lock-only
74
-
75
108
  - name: Restore npm cache
76
109
  uses: actions/cache@v4
77
110
  with:
78
111
  path: ~/.npm
79
- key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
112
+ key: npm-${{ runner.os }}-${{ hashFiles('site/package-lock.json') }}
80
113
  restore-keys: npm-${{ runner.os }}-
81
114
 
82
- - name: Sync lockfile and install
115
+ - name: Install dependencies
116
+ working-directory: site
83
117
  run: |
84
- npm install --package-lock-only
85
- if ! git diff --quiet package-lock.json 2>/dev/null; then
86
- git config user.name "github-actions[bot]"
87
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
88
- git add package-lock.json
89
- git commit -m "chore: sync package-lock.json"
90
- git push || echo "Lockfile push failed (remote ahead); proceeding with deploy"
118
+ if [ ! -f package-lock.json ]; then
119
+ npm install --package-lock-only
91
120
  fi
92
121
  npm ci
93
122
 
94
123
  - name: Build
124
+ working-directory: site
95
125
  run: npm run build
96
126
 
97
- - name: Resolve site manifest
98
- id: site
99
- run: node .deco-start/scripts/deploy/resolve-site.mjs
100
- env:
101
- DECO_START_PATH: .deco-start
102
- SITE_NAME: ${{ steps.meta.outputs.site_name }}
103
-
104
- - name: Generate wrangler.jsonc
105
- run: node .deco-start/scripts/deploy/build-wrangler-config.mjs
127
+ - name: Generate wrangler.jsonc from template
128
+ working-directory: site
106
129
  env:
107
- DECO_START_PATH: .deco-start
108
- SITE_NAME: ${{ steps.meta.outputs.site_name }}
109
- OUTPUT_PATH: ./wrangler.jsonc
130
+ DECO_START_PATH: "${{ github.workspace }}"
131
+ WORKER_NAME: ${{ inputs.site_name }}
132
+ OUTPUT_PATH: "./wrangler.jsonc"
133
+ run: node "$DECO_START_PATH/scripts/deploy/build-wrangler-config.mjs"
110
134
 
111
135
  - name: Deploy to Cloudflare Workers
112
- run: npx wrangler deploy --var BUILD_HASH:$(git rev-parse --short HEAD)
136
+ working-directory: site
113
137
  env:
114
138
  CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
115
139
  CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
140
+ BUILD_HASH: ${{ steps.target.outputs.sha }}
141
+ run: npx wrangler deploy --var "BUILD_HASH:${BUILD_HASH:0:7}"