Skip to content

fix(codesign): sign bundles with spaced paths; fail loudly on signing errors#116

Open
sepehr-safari wants to merge 1 commit into
vercel-labs:mainfrom
sepehr-safari:fix/codesign-spaced-path
Open

fix(codesign): sign bundles with spaced paths; fail loudly on signing errors#116
sepehr-safari wants to merge 1 commit into
vercel-labs:mainfrom
sepehr-safari:fix/codesign-spaced-path

Conversation

@sepehr-safari

Copy link
Copy Markdown
Contributor

Summary

native package --signing adhoc|identity silently shipped an unsigned macOS bundle when the output path contained spaces (e.g. My App.app). The command exited 0, so a release built this way was broken with no error surfaced — on Apple silicon the unsigned bundle fails codesign --verify and does not launch cleanly.

Fixes #115.

Root cause

src/tooling/codesign.zig composed the codesign invocation as a shell string run via sh -c, with the bundle path concatenated unquoted. A spaced path word-split (…/My App.app…/My, App.app), so codesign errored with …/My: No such file or directory. runSigning() in src/tooling/package.zig then swallowed the failure — it noted the unsigned state in signing-plan.txt and returned normally, so native package still exited 0.

Fix

  • Argv, not sh -c. codesign / notarytool / stapler / ditto are now built as argv arrays and spawned directly (matching the existing src/tooling/ios.zig idiom). Passing argv straight to the OS keeps a spaced path a single argument and removes the shell command-injection surface from paths and identities.
  • Fail loudly. When signing was requested and codesign actually ran and failed — or --signing identity is given no --identity — packaging now records the unsigned state and exits non-zero with a clear message, instead of shipping a broken bundle silently. A host that genuinely cannot sign (cross-packaging a macOS bundle off macOS, where codesign does not exist) stays tolerant and still succeeds with an unsigned bundle.
  • Regression gate. test-package-signing now packages to a spaced output path, so the exact scenario is covered end to end. New argv unit tests pin spaced paths as single arguments.

Verification

  • zig build test — full suite green.
  • scripts/gate.sh fast — all affected suites green.
  • zig build test-package-signing (now a spaced path) — codesign --verify --strict --deep passes; signature is flags=0x2(adhoc) (a real bundle seal, not the previous 0x20002(adhoc,linker-signed)).
  • Manual end-to-end on macOS/arm64:
    • package --signing adhoc --output "…/My App.app" → exit 0, verify passes.
    • bogus --identity (codesign runs & fails) → exit 1 + clear message.
    • --signing identity with no --identity → exit 1 + clear message.
    • --signing none → exit 0 (unchanged).

Changelog

Adds a fix: fragment under changelog.d/.

… errors

`native package --signing adhoc|identity` composed the codesign invocation
as a shell string run via `sh -c`, with the bundle path concatenated
unquoted. An output path like "My App.app" word-split into "My" and
"App.app", so codesign signed nothing and the command still exited 0 with
an unsigned bundle (only the linker's inner-binary signature remained) —
broken on Apple silicon with no error surfaced.

Build the codesign / notarytool / stapler / ditto invocations as argv
arrays spawned directly instead of `sh -c` strings. Passing argv straight
to the OS keeps a spaced path a single argument and removes the command-
injection surface from paths and identities.

Make signing failures loud: when codesign runs and fails (or `--signing
identity` is given no `--identity`), record the unsigned state in the
signing plan and exit non-zero instead of shipping a broken bundle
silently. A host that simply cannot sign (cross-packaging a macOS bundle
off macOS, where codesign does not exist) stays tolerant and still
succeeds with an unsigned bundle.

Harden the test-package-signing gate to package to a spaced output path so
the exact regression is covered end to end, and add argv unit tests that
pin spaced paths as single arguments.

Fixes vercel-labs#115.
@vercel

vercel Bot commented Jul 12, 2026

Copy link
Copy Markdown

@sepehr-safari is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

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.

native package silently ships an UNSIGNED macOS bundle when the output path contains spaces

1 participant