Public Access
The same application, the same Velopack and the same two-phase person-run release as Windows, with four things forced to differ. Signing is a precondition rather than an improvement: Gatekeeper refuses an un-notarized download outright instead of warning about it, so there was never the "unsigned for now" that ADR 0013 decision 8 argues for on Windows, and release-macos.sh refuses to start without the identities. The packaging split is narrower than it first looked, and the old claim at the foot of ci.yml is why it was worth checking rather than assuming. vpk cross-compiles when told to: 'vpk [osx] bundle' builds a real .app on any platform, and CI now publishes osx-arm64 and bundles it on every main and tag build, which is what catches a restore graph with no macOS native asset. There is no '[osx] pack' off a Mac, and that part is correct — pack drives codesign, notarytool and stapler, which exist nowhere else. The dylib signing loop in the script looks redundant beside vpk's own pass and is not. vpk signs with 'codesign --deep', which is the shape Apple documents as wrong for nested code, and platform-flags has recorded a notarization rejection that names no file since before any of this existed. Signing each native binary inside-out first leaves that pass nothing to get wrong. MacDeviceKeyStore reaches ADR 0007's conclusion through different hardware: a P-256 key in the Secure Enclave under an access control requiring user presence, so the platform enforces the gate rather than this process — which is the whole point of that ADR's amendment. The enclave holds no other kind of key, hence ECIES where Windows uses RSA-OAEP, and the shape that falls out is better than the Windows one: sealing needs only the public half and is silent, so only unlock prompts. IsSupported probes rather than infers, because three ordinary Macs answer no — an Intel machine without a T2, one with no login password, and every unsigned development build, since enclave keys need a signing identity. Two decisions worth stating because they are reversible. arm64 only: a second channel is small work and nobody here has an Intel Mac to walk Phase 18 on, and an x64 package would be the only artefact in this repository reaching users unverified. And the pack id stays DodoSSH.Desktop even though vpk names the bundle after it, so /Applications holds DodoSSH.Desktop.app: decision 2's reasoning binds harder here, because a pack id of DodoSSH would put Velopack's install root on top of ClientPaths.DataDirectory and let an uninstall take the user's un-synced outbox with it. CFBundleDisplayName puts the product name back in front of a person. Measured rather than assumed, since none of it is obvious: the publish and the bundle were both run, LSMinimumSystemVersion is 12.0 because that is the minos in the apphost's own LC_BUILD_VERSION, and vpk copies a custom Info.plist verbatim with no substitution at all — which is why the plist is a template the script renders and not a committed file. What is not done is the half that needs the hardware. There is no macOS runner, so nothing past "it bundles" has ever run. Phase 18 is the whole of the verification, and the two checks most likely to fail are the terminal against WKWebView and the enclave interop, neither of which has executed once.
68 lines
3.6 KiB
XML
68 lines
3.6 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!--
|
|
What the hardened runtime has to be asked to relax before a .NET application will run under it.
|
|
|
|
The hardened runtime is not optional: notarization refuses a Developer ID submission without it,
|
|
and Gatekeeper refuses an un-notarized download. So every entitlement below is the price of being
|
|
distributable at all, and each one is a hole in a wall that is otherwise worth having. They are
|
|
listed one at a time, with what breaks without each, because the temptation when notarization
|
|
fails at eleven at night is to paste in a longer list from somewhere and stop thinking.
|
|
|
|
◆ WHAT IS DELIBERATELY NOT HERE.
|
|
|
|
com.apple.security.app-sandbox. Developer ID distribution outside the App Store does not require
|
|
the sandbox, and turning it on would break the product outright: the terminal's data plane is a
|
|
loopback WebSocket (see DodoSSH.Client.Terminal/TerminalDataPlane.cs), and a sandboxed process
|
|
needs com.apple.security.network.server to listen at all, plus network.client to reach any host
|
|
the user asks for. This is the same shape of decision as ruling out MSIX on Windows, which was
|
|
ruled out for the same loopback reason — docs/platform-flags.md.
|
|
|
|
com.apple.security.cs.debugger. Would let this process attach to others. Nothing here debugs
|
|
anything, and it is the entitlement most worth not having.
|
|
-->
|
|
<plist version="1.0">
|
|
<dict>
|
|
<!--
|
|
CoreCLR compiles IL to machine code at runtime and then executes the pages it just wrote. The
|
|
hardened runtime's default is that no page is both writable and executable, so without this the
|
|
process does not start — it dies during runtime initialisation, before any of this application's
|
|
code runs, which means before anything exists that could report it.
|
|
-->
|
|
<key>com.apple.security.cs.allow-jit</key>
|
|
<true/>
|
|
|
|
<!--
|
|
The broader form of the same permission, and it is needed as well as allow-jit rather than
|
|
instead of it. allow-jit covers pages mapped through the MAP_JIT convention; CoreCLR also
|
|
allocates executable memory outside that path — stubs, precode, and the write-xor-execute
|
|
fallback it uses when MAP_JIT is unavailable. With only the first, startup gets further and
|
|
still fails.
|
|
-->
|
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
|
<true/>
|
|
|
|
<!--
|
|
Library validation requires every loaded dylib to be signed by the same team as the main
|
|
binary. This bundle carries native libraries built by other people — libsodium, libSkiaSharp,
|
|
libHarfBuzzSharp, libe_sqlite3, libAvaloniaNative — and the release script signs each of them
|
|
with this Developer ID, which would in principle satisfy validation.
|
|
|
|
It is disabled anyway, and the reason is the updater. Velopack replaces the bundle in place and
|
|
relaunches it, and the process doing the replacing is not always signed by the same team as the
|
|
process being replaced during the changeover. Leaving validation on makes the failure mode of a
|
|
bad update "the application will not start", with no way to recover except a reinstall the user
|
|
would have to be told about through some other channel.
|
|
-->
|
|
<key>com.apple.security.cs.disable-library-validation</key>
|
|
<true/>
|
|
|
|
<!--
|
|
The runtime reads DYLD_ variables while resolving its own native dependencies, and Velopack's
|
|
update path sets them. Without this the hardened runtime strips them silently and the failure
|
|
surfaces later as a library that cannot be found, naming a file that is plainly present.
|
|
-->
|
|
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
|
<true/>
|
|
</dict>
|
|
</plist>
|