Skip to content

Self-packaging #8: macOS notarised — reserved-segment variant + re-sign #48

@jrosskopf

Description

@jrosskopf

Part of epic #40. Depends on #5 (pack subcommand).

Goal

Produce a bundled macOS binary that is notarisable, not just
ad-hoc signable. Mach-O is the awkward case: appending bytes after
__LINKEDIT invalidates a signature. Solution: pre-allocate a
placeholder segment at link time, overwrite it with the archive at
pack time, then re-sign.

Scope

Link-time placeholder

Top-level CMakeLists.txt (macOS branch only):

  • Add FLAPI_RESERVED_BUNDLE_MIB CMake option, default 16.
  • Generate a <build>/_flapi_bundle_placeholder.bin file of N MiB of
    zeros.
  • Link the flapi executable with
    -Wl,-sectcreate,__FLAPI,__bundle,<path/to/placeholder.bin>.
  • Section must be placed before __LINKEDIT (linker default is
    usually fine; assert in CI via otool -l | grep -A1 __LINKEDIT).

Pack-time overwrite

In src/pack.cpp (the macOS branch):

  • Detect Mach-O magic on the output file.
  • Locate the __FLAPI/__bundle section (parse load commands).
  • If archive_size > section_size: print a clear error
    ("Bundle is N MiB; reserved segment is M MiB. Rebuild flapi with
    -DFLAPI_RESERVED_BUNDLE_MIB=N+slack."), exit non-zero.
  • Otherwise: overwrite the segment in place, zero-pad the slack so
    the EOCD still self-locates relative to segment EOF (the EOCD
    goes inside the segment, not at file EOF).
  • Invoke codesign --force --sign "$CODESIGN_IDENTITY" <out>. Falls
    back to --sign - (ad-hoc) when the env var is unset.

Legacy --macos-append flag

  • Explicit opt-in to the trailing-append flow (the
    Linux/Windows behaviour) on macOS.
  • Ad-hoc signing only; warn that the result is not notarisable.
  • Kept for parity with the spike and for users who don't need
    notarisation.

Red tests (test/integration/test_self_packaging_macos.py, skipped on non-Darwin)

  1. Reserved-segment pack succeeds → codesign --verify <out> passes.
  2. Bundled binary still self-locates the archive (EOCD inside the
    __FLAPI/__bundle section is unchanged).
  3. Oversized input → non-zero exit with the corrective message.
  4. --macos-append mode still works (signature allowed to be
    warning-only).

Green criteria

  • All red tests pass on macos-latest.
  • otool -l <flapi> shows __FLAPI/__bundle exists and is sized
    per FLAPI_RESERVED_BUNDLE_MIB.
  • codesign --verify --deep --strict <flapi-prod> exits 0 on the
    reserved-segment path.
  • Linux and Windows builds unaffected.

Files

  • Modified: CMakeLists.txt, src/pack.cpp, src/main.cpp (flag
    wiring)
  • New: test/integration/test_self_packaging_macos.py

References

  • Spike notes on the macOS trade-off — section "Cross-OS reality" in
    the spike README.
  • The reserved-segment approach is industry-standard (AppImage,
    PyInstaller, Wails all use variants).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions