• 0.0.8 061ae098da

    Sign builds and releases with a stable code identity

    bdeshi released this 2026-08-05 13:23:09 +06:00 | 10 commits to main since this release

    swiftc linker-signs only the inner binary, leaving the bundle unsigned
    and its codesign identifier as "launcher" rather than the bundle id. More
    importantly it leaves the app ad-hoc signed, and macOS pins an ad-hoc
    app's Accessibility grant to its exact cdhash instead of to a designated
    requirement. Every build mints a new cdhash, so each rebuild-and-replace
    silently revoked the permission while the app stayed listed and ticked
    under Privacy & Security — and every release did the same to everyone who
    updated. That was the root cause of the window tags never appearing.

    • build.sh signs the bundle with its real identifier, honours
      SHANNONCOAT_SIGN_IDENTITY, and fails outright rather than falling back
      to ad-hoc when an identity was asked for explicitly.
    • The identity is read from a gitignored .env, so it doesn't have to be
      retyped every build. Parsed rather than sourced, so a stray command in
      the file can't execute as a side effect of building, and so an existing
      environment variable still wins. .env.example carries the full one-time
      setup.
    • release.yml imports the certificate into a throwaway keychain, builds,
      verifies, and deletes the keychain on if: always(). It stays inert
      until the three secrets exist, and fails the release rather than
      shipping ad-hoc.
    • Guards the empty-password case explicitly: macOS cannot import an
      OpenSSL-produced PKCS#12 with an empty password, and reports it as "MAC
      verification failed (wrong password?)", which sends you hunting for a
      wrong password rather than a missing one. Nothing local catches this,
      since the login keychain imports the PEM pair and needs no password.
    • Ignores *.p12 and *.pem as a backstop; the certificate belongs outside
      the working tree entirely.

    Verified end-to-end: two from-scratch builds produce byte-identical
    designated requirements where ad-hoc differs every time, and six
    rebuild-reinstall cycles under a real certificate kept the Accessibility
    grant with no System Settings interaction.

    This buys permission persistence, not Gatekeeper approval — a
    self-signed certificate isn't notarized, so downloads still need
    System Settings -> Privacy & Security -> Open Anyway.

    Downloads