Skip to content

Commit 6acfeb3

Browse files
authored
fix(desktop): keep signed release builds off shared caches (#9701)
Restore no caches in the signed build job, and require a manual dispatch to run from the tag it builds, so it never executes another ref's code in a run that can write default-branch caches.
1 parent 45e36ff commit 6acfeb3

3 files changed

Lines changed: 12 additions & 38 deletions

File tree

‎.github/workflows/desktop-release.yml‎

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,16 @@ jobs:
6565
runs-on: ubuntu-24.04
6666
timeout-minutes: 5
6767
outputs:
68-
commit: ${{ steps.source.outputs.commit }}
6968
name: ${{ steps.channel.outputs.name }}
7069
app_id: ${{ steps.channel.outputs.app_id }}
7170
origin: ${{ steps.channel.outputs.origin }}
7271
release_repository: ${{ steps.channel.outputs.release_repository }}
7372
token_kind: ${{ steps.channel.outputs.token_kind }}
74-
smoke_shards: ${{ steps.smoke.outputs.shards }}
7573
steps:
7674
- name: Checkout code
7775
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
7876
with:
7977
persist-credentials: false
80-
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.version || github.sha }}
8178

8279
# Prerelease versions carry their environment in the tag: -dev.N is a
8380
# dev build, -staging.N a staging build. Legacy -alpha/-beta tags remain
@@ -108,7 +105,6 @@ jobs:
108105
echo "Building $NAME ($APP_ID) for $RELEASE_REPOSITORY; default origin: ${ORIGIN:-production}"
109106
110107
- name: Validate release source
111-
id: source
112108
env:
113109
PUBLISH: ${{ inputs.publish }}
114110
SIGN: ${{ inputs.sign }}
@@ -123,6 +119,10 @@ jobs:
123119
echo "::error::Manual desktop releases must use a stable source-repository tag."
124120
exit 1
125121
fi
122+
if [ "$GITHUB_EVENT_NAME" = workflow_dispatch ] && [ "$GITHUB_REF" != "refs/tags/$VERSION" ]; then
123+
echo "::error::Run this workflow from the $VERSION tag, so it executes only that tag's code and its caches stay scoped to that tag."
124+
exit 1
125+
fi
126126
if [ "$PUBLISH" = true ] && [ "$SIGN" != true ]; then
127127
echo "::error::Desktop releases must be signed before publication."
128128
exit 1
@@ -137,17 +137,6 @@ jobs:
137137
fi
138138
fi
139139
140-
echo "commit=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
141-
142-
- name: Select available smoke partitioning
143-
id: smoke
144-
run: |
145-
if [ -f scripts/desktop-e2e.ts ]; then
146-
echo 'shards=[1,2,3,4]' >> "$GITHUB_OUTPUT"
147-
else
148-
echo 'shards=[1]' >> "$GITHUB_OUTPUT"
149-
fi
150-
151140
- name: Validate release authentication
152141
if: ${{ inputs.publish }}
153142
env:
@@ -168,14 +157,13 @@ jobs:
168157
strategy:
169158
fail-fast: false
170159
matrix:
171-
shard: ${{ fromJSON(needs.source.outputs.smoke_shards) }}
160+
shard: [1, 2, 3, 4]
172161
steps:
173162
- &checkout-source
174163
name: Checkout verified source
175164
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
176165
with:
177166
persist-credentials: false
178-
ref: ${{ needs.source.outputs.commit }}
179167

180168
- &setup-bun
181169
name: Setup Bun
@@ -218,9 +206,7 @@ jobs:
218206
exit 1
219207
fi
220208
221-
- &native-cache
222-
name: Restore native compilation
223-
if: hashFiles('.github/actions/desktop-native-cache/action.yml') != ''
209+
- name: Restore native compilation
224210
uses: ./.github/actions/desktop-native-cache
225211

226212
- &bundle-desktop
@@ -245,12 +231,7 @@ jobs:
245231
BACKGROUND_EXECUTOR_REPORT_PATH: test-results/background-executor-report.json
246232
TERMINAL_CANCEL_REPORT_PATH: test-results/terminal-cancel-report.json
247233
CONTINUE_SIGN_IN_REPORT_PATH: test-results/continue-sign-in-report.json
248-
run: |
249-
if [ -f ../../scripts/desktop-e2e.ts ]; then
250-
bun run ../../scripts/desktop-e2e.ts ${{ matrix.shard }}/${{ strategy.job-total }}
251-
else
252-
bun run test:e2e --reporter=line,json
253-
fi
234+
run: bun run ../../scripts/desktop-e2e.ts ${{ matrix.shard }}/${{ strategy.job-total }}
254235

255236
- name: Upload smoke coverage and timings
256237
if: always()
@@ -271,6 +252,8 @@ jobs:
271252
if-no-files-found: ignore
272253
retention-days: 7
273254

255+
# Restores no caches: every byte that gets signed comes from this checkout or
256+
# a fresh download, never from a cache another run could have written.
274257
build:
275258
name: build
276259
needs: source
@@ -285,20 +268,10 @@ jobs:
285268

286269
- *setup-node
287270

288-
- name: Cache Electron binaries
289-
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
290-
with:
291-
path: |
292-
~/Library/Caches/electron
293-
~/Library/Caches/electron-builder
294-
key: electron-cache-${{ runner.os }}-${{ hashFiles('apps/desktop/package.json') }}
295-
296271
- *install-dependencies
297272

298273
- *inject-version
299274

300-
- *native-cache
301-
302275
- name: Verify desktop source
303276
run: |
304277
bun run --cwd apps/desktop lint:check

‎apps/desktop/README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ The build also derives the app icon from `SIM_DESKTOP_DEFAULT_ORIGIN`. Every cha
108108

109109
CI (`.github/workflows/desktop-release.yml`, wired into `ci.yml`):
110110
- Stable builds run only after `release` on a `vX.Y.Z:` commit to main — **never before**: `scripts/create-single-release.ts` skips creation if the tag exists, so a desktop job publishing first would eat the changelog. Stable assets remain on `simstudioai/sim`; dev/staging assets publish to the public `simstudioai/sim-desktop-releases` repository so source-repository followers are not notified for internal shell builds. The job builds `--publish never`; reruns verify the size and SHA-256 digest of existing release assets instead of overwriting them.
111-
- **Secrets gate**: `desktop-signing` in `ci.yml` probes the six Apple secrets and skips the desktop job with a warning until they exist — releases never fail on a missing Apple account, and the first release after the secrets land ships desktop artifacts automatically. Manual/one-off builds: Actions → "desktop-release" → Run workflow with a `vX.Y.Z` version (`publish: false` uploads artifacts to the run instead of the release).
111+
- **Secrets gate**: `desktop-signing` in `ci.yml` probes the six Apple secrets and skips the desktop job with a warning until they exist — releases never fail on a missing Apple account, and the first release after the secrets land ships desktop artifacts automatically. Manual/one-off builds: Actions → "desktop-release" → Run workflow, select the `vX.Y.Z` tag under "Use workflow from", and enter the same version (`publish: false` uploads artifacts to the run instead of the release). Any other ref is refused, so a run only executes the tag's own code and workflow, and its caches stay scoped to that tag.
112+
- **Cache trust**: the signed `build` job restores no caches, so nothing it signs can come from a cache another run wrote. Only the unsigned smoke jobs use caches.
112113
- The product semver is **injected** from the release tag into `apps/desktop/package.json` at build time (repo package versions are placeholders). A mismatch guard fails the build.
113114
- Fuses are flipped at package time (`electronFuses` in `electron-builder.yml`): runAsNode off, NODE_OPTIONS off, inspect args off, ASAR-only + integrity validation, and cookie encryption on. The packaged smoke test asserts every fuse byte so Electron upgrades fail until new fuses receive an explicit policy.
114115
- **Cookie-encryption go/no-go**: on every Electron bump, verify a packaged build keeps its session across relaunch (there are historical cookie-persistence bugs with the `EnableCookieEncryption` fuse). If it reproduces, set `enableCookieEncryption: false` and record it here.

‎apps/desktop/docs/electron-upgrade-checklist.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ The rendering-parity guarantee (identical to Chrome of the pinned version) is on
1313
- Workflow canvas (WebGL/ReactFlow), Monaco editing, a table export download.
1414
- Offline page appears with networking off; Retry recovers.
1515
6. **E2E:** `bun run test:e2e` green locally on the new pin; `desktop-e2e.yml` green in CI (the `latest` canary leg should already have hinted at surprises).
16-
7. **Signing/notarization smoke:** run `desktop-release.yml` via `workflow_dispatch` with `publish: false` against a test tag; `spctl`/`stapler` steps must pass.
16+
7. **Signing/notarization smoke:** run `desktop-release.yml` via `workflow_dispatch` with `publish: false`, selecting a test tag under "Use workflow from" and entering the same version; `spctl`/`stapler` steps must pass.
1717
8. **Ship** behind a staged rollout (10% `stagingPercentage`) and watch `update_error` / `renderer_gone` rates in the event logs before raising.

0 commit comments

Comments
 (0)