Skip to content

fix(release): smoke test a copy so the shipped bundle stays sealed - #21

Merged
amondnet merged 1 commit into
mainfrom
fix/smoke-test-preserves-seal
Jul 28, 2026
Merged

fix(release): smoke test a copy so the shipped bundle stays sealed#21
amondnet merged 1 commit into
mainfrom
fix/smoke-test-preserves-seal

Conversation

@amondnet

@amondnet amondnet commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

The failure

v0.2.1's release run failed notarization on both arches with one issue:

path:         OpenHWP-darwin-arm64.dmg/OpenHWP.app/Contents/MacOS/laufey
message:      The signature of the binary is invalid.
architecture: arm64

The signature was not invalid. The bundle was modified after it was signed.

Cause

On a successful start the app writes a 2-byte marker into its own bundle:

Contents/MacOS/laufey.dylib.update-ok   ("ok")

That file is not sealed by the signature, so the bundle stops verifying:

$ codesign --verify --deep --strict OpenHWP.app
OpenHWP.app: a sealed resource is missing or invalid
file added: .../Contents/MacOS/laufey.dylib.update-ok

The smoke test added in #20 launched the bundle we ship, between signing and
packaging — so it broke the exact artifact it existed to verify. v0.2.0
notarized only because it never launched the app.

The signing step itself is correct: codesign --verify --deep --strict passes
right after signing, and the smoke test proved the JIT entitlements work
(Listening on http://127.0.0.1:49202/ on arm64, :49207 on x64). Only the
order of operations was wrong.

Fix

  1. Launch a byte-identical copy in $RUNNER_TEMP. The copy absorbs the
    marker; the shipped bundle is never executed. Launching the copy still
    proves the same bits run.
  2. Re-verify the bundle immediately before hdiutil. Any future mutation
    under Contents/ now fails in seconds naming the offending path, instead of
    returning as an opaque notary rejection ten minutes later.

Verification

Reproduced and fixed locally against a real deno desktop build:

check result
marker appears in the copy laufey.dylib.update-ok present
marker in the shipped bundle none
shipped bundle after smoke test valid on disk / satisfies its Designated Requirement
smoke test still proves launch Listening on http://127.0.0.1:60649/
new gate, marker present exit 1
new gate, marker absent exit 0

The gate was checked against the real mutation, not just asserted — this
session has already shipped two guards that passed vacuously.


Summary by cubic

Prevented notarization failures by smoke-testing a byte-identical copy of the macOS app instead of the signed bundle, and by re-verifying the signature before DMG packaging. This keeps the shipped bundle sealed and catches mutations early.

  • Bug Fixes
    • Launch a copy in $RUNNER_TEMP so the startup marker file lands in the copy, not the bundle we ship.
    • Re-run codesign --verify --deep --strict --verbose=2 on the bundle right before hdiutil to fail fast if anything under Contents/ changed.

Written for commit 94c3622. Summary will update on new commits.

v0.2.1 notarized as Invalid on both arches with a single issue:

  path:    OpenHWP.app/Contents/MacOS/laufey
  message: The signature of the binary is invalid.

The signature was fine. On a successful start the app writes a 2-byte
marker, Contents/MacOS/laufey.dylib.update-ok, into its own bundle. That
adds a file the signature does not seal:

  codesign --verify --deep --strict
    a sealed resource is missing or invalid
    file added: .../Contents/MacOS/laufey.dylib.update-ok

so the smoke test added in #20 broke the very artifact it was verifying,
between signing and packaging. v0.2.0 notarized only because it never
launched the app.

Launch a byte-identical copy in $RUNNER_TEMP instead. The copy absorbs
the marker and the shipped bundle is never executed. Reproduced and
verified locally: the copy gets the marker, the shipped bundle does not
and still reports "valid on disk / satisfies its Designated Requirement",
and the smoke test still logs "Listening on".

Also re-verify the bundle immediately before hdiutil. Any future mutation
under Contents/ now fails in seconds with the offending path named,
instead of coming back as an opaque notarization rejection ten minutes
later. Confirmed to exit 1 with the marker present and 0 without it.
@gemini-code-assist

Copy link
Copy Markdown

Note

Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported.

@sonarqubecloud

Copy link
Copy Markdown

@greptile-apps

greptile-apps Bot commented Jul 28, 2026

Copy link
Copy Markdown

Greptile Summary

The release workflow preserves the signed application bundle during smoke testing.

  • Copies the signed app into the runner’s temporary directory and launches that copy.
  • Re-verifies the original app’s signature immediately before DMG staging.

Confidence Score: 5/5

The PR appears safe to merge, with the shipped bundle kept isolated from the known startup mutation and verified before packaging.

The smoke process launches only the temporary copy, failures in copying or verification stop the workflow, and the verified original bundle is the source subsequently copied into DMG staging.

Important Files Changed

Filename Overview
.github/workflows/release.yml Smoke testing now runs against an isolated bundle copy, while the original signed bundle is verified again before packaging.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Sign OpenHWP.app] --> B[Verify signed app]
    B --> C[Copy app to RUNNER_TEMP]
    C --> D[Smoke-test copied app]
    D --> E[Verify original app again]
    E --> F[Copy original app into DMG staging]
    F --> G[Build and sign DMG]
Loading

Reviews (1): Last reviewed commit: "fix(release): smoke test a copy so the s..." | Re-trigger Greptile

@amondnet
amondnet merged commit c7f7232 into main Jul 28, 2026
13 checks passed
@amondnet
amondnet deleted the fix/smoke-test-preserves-seal branch July 28, 2026 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant