You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Three improvements to release-desktop.yml that together make the
0.10.17-0.10.21 failure class (a published release tag pointing at
unopenable bundles) structurally impossible to ship.
Inline verification on each macOS matrix row, after tauri-action:
1. codesign authority must match "Developer ID Application:
Forward Email LLC" with TeamIdentifier FH83QMJS7P.
2. spctl reports "source=Notarized Developer ID" (Gatekeeper would
accept).
3. Entitlement allowlist: explicit refusal of aps-environment with
a doc-pointer error message naming the postmortem, so the next
person who hits this finds the writeup in one search.
4. Launch-survives test: exec the binary, sleep 3 seconds, assert
the process is still alive. Catches taskgated rejection (the
0.10.17-0.10.21 bug class) because taskgated kills the process
within ~50ms of exec — well within the 3s window.
E2E gate (new): release-desktop.yml now calls e2e-webview.yml via
workflow_call with release_gate=true. The e2e matrix (Linux 22.04,
Linux 24.04, Windows x64, macOS arm64, macOS x64) runs in parallel
with the build matrix as a gate. Catches platform-native crash
classes (NSOpenPanel, WebKit insets, attachment OOM) that the 3s
launch smoke can't exercise on its own.
Release gate (Layer 4):
- tauri-action now uploads to a DRAFT release unconditionally.
- New publish-release job depends on both build-and-release AND
e2e-webview-gate. Uses `gh release edit --draft=false` to promote
draft → published. If any row in either matrix fails, this job
is skipped by default GitHub Actions `needs:` semantics, leaving
the release as a draft for inspection.
Net: a release tag becomes user-visible ONLY after every build row
succeeded, every signing + structural assert + launch smoke passed,
AND every e2e row passed. Adds ~15-20 min to the release critical
path; trades release speed for release confidence.
See docs/desktop-postmortem-macos-entitlements-2026-05-19.md for the
incident this guards against.
echo "::error::Bundle not found at $APP — tauri-action did not produce a .app"
259
+
exit 1
260
+
fi
261
+
262
+
echo "=== 1. codesign authority ==="
263
+
if ! codesign -dv --verbose=4 "$APP" 2>&1 | tee /tmp/cs.out; then
264
+
echo "::error::codesign -dv failed — bundle is not signed"
265
+
exit 1
266
+
fi
267
+
if ! grep -q "Authority=Developer ID Application: Forward Email LLC" /tmp/cs.out; then
268
+
echo "::error::Bundle is not signed with Forward Email LLC Developer ID"
269
+
grep "Authority=" /tmp/cs.out || true
270
+
exit 1
271
+
fi
272
+
if ! grep -q "TeamIdentifier=FH83QMJS7P" /tmp/cs.out; then
273
+
echo "::error::Bundle TeamIdentifier does not match Forward Email LLC (FH83QMJS7P)"
274
+
exit 1
275
+
fi
276
+
277
+
echo "=== 2. spctl notarization ==="
278
+
if ! spctl -a -vvv "$APP" 2>&1 | tee /tmp/spctl.out; then
279
+
echo "::error::spctl rejects the bundle"
280
+
exit 1
281
+
fi
282
+
if ! grep -q "Notarized Developer ID" /tmp/spctl.out; then
283
+
echo "::error::Bundle is not notarized — Gatekeeper would reject it"
284
+
exit 1
285
+
fi
286
+
287
+
echo "=== 3. entitlement allowlist ==="
288
+
codesign -d --entitlements - "$APP" 2>&1 | tee /tmp/ents.out
289
+
if grep -q "aps-environment" /tmp/ents.out; then
290
+
echo "::error::aps-environment entitlement present on macOS Developer ID bundle. The Forward Email LLC cert is not APNs-authorized; the kernel will SIGKILL on launch. See docs/desktop-postmortem-macos-entitlements-2026-05-19.md"
291
+
exit 1
292
+
fi
293
+
294
+
echo "=== 4. launch-survives test (3s) ==="
295
+
"$BIN" >/tmp/launch.out 2>&1 &
296
+
PID=$!
297
+
sleep 3
298
+
if kill -0 "$PID" 2>/dev/null; then
299
+
echo "Bundle survived 3 seconds — codesign/entitlements look OK at exec time"
300
+
kill "$PID" 2>/dev/null || true
301
+
wait "$PID" 2>/dev/null || true
302
+
else
303
+
echo "::error::Binary exited within 3s of launch. This indicates taskgated rejected the signed bundle — usually an entitlement-vs-cert mismatch. Last output from the binary:"
304
+
cat /tmp/launch.out || true
305
+
echo ""
306
+
echo "Searching for matching crash log…"
307
+
log show --predicate 'process == "forwardemail-desktop" AND messageType == fault' --last 1m 2>/dev/null | head -40 || true
308
+
exit 1
309
+
fi
310
+
227
311
# SLSA build provenance attestation. Publishes a signed attestation
228
312
# to the Sigstore transparency log binding each desktop bundle to
0 commit comments