mirror of
https://github.com/priyanshujain/margin-docs.git
synced 2026-10-02 11:07:05 +00:00
feature fixes
This commit is contained in:
1 parent
586ee946d0
commit
c1c47bc513
63 files changed
+12083
-229
No files matched your search
+75
-17
@@ -23,12 +23,16 @@ and `src-tauri/Cargo.toml` together, commits that to main, tags it, and builds t
|
||||
whatever main happens to be by then.
|
||||
|
||||
It builds one universal macOS bundle and publishes nothing until it has landed. The last job
|
||||
downloads `latest.json` and refuses to take the release out of draft unless `darwin-aarch64` and
|
||||
`darwin-x86_64` are both present in it. One universal build writes both of those keys, pointing
|
||||
them at the same archive and the same signature, because an installed copy asks the manifest for
|
||||
the architecture it is running on and never for a universal one. A half-populated manifest is worse
|
||||
than no release at all: the updater would offer an update to the platforms that made it and error
|
||||
on the ones that did not.
|
||||
downloads `latest.json` and refuses to take the release out of draft unless three things hold: the
|
||||
version in the manifest is the version in the tag, `darwin-aarch64` and `darwin-x86_64` are both
|
||||
present, and each of them has a signature as well as a url. One universal build writes both of
|
||||
those keys, pointing them at the same archive and the same signature, because an installed copy
|
||||
asks the manifest for the architecture it is running on and never for a universal one. A
|
||||
half-populated manifest is worse than no release at all: the updater would offer an update to the
|
||||
platforms that made it and error on the ones that did not. A manifest carrying the version before
|
||||
this one is worse again, because it tells everybody the copy they are already running is the newest
|
||||
there is, and an entry with an empty signature is an update every installed copy downloads and then
|
||||
refuses.
|
||||
|
||||
Linux is not built. It was until recently, because this pipeline was copied from margin-calendar,
|
||||
which ships on Linux. This app does not, so the row and the manifest key it required are gone and
|
||||
@@ -38,17 +42,54 @@ Windows is not built. Nothing in `tauri.conf.json` targets it and the app has ne
|
||||
|
||||
## What the build needs
|
||||
|
||||
Two repository secrets: `TAURI_SIGNING_PRIVATE_KEY` and `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`,
|
||||
which sign the updater artifacts so an installed copy can tell a real update from anything else
|
||||
offered at the same URL. The public half lives in `src-tauri/tauri.release.conf.json`, baked into
|
||||
every build, so the private half can never be rotated without stranding everyone who has not
|
||||
updated yet; back up the key and its password somewhere that is not the machine that generated
|
||||
them. That file currently carries the placeholder `REPLACE_WITH_TAURI_SIGNER_PUBKEY`; generating
|
||||
the real keypair and committing its public half in is a one-time step that has to happen before the
|
||||
first signed release can go out.
|
||||
Two repository secrets sign the updater artifacts, so that an installed copy can tell a real update
|
||||
from anything else offered at the same URL: `TAURI_SIGNING_PRIVATE_KEY` and
|
||||
`TAURI_SIGNING_PRIVATE_KEY_PASSWORD`. The public half lives in
|
||||
`src-tauri/tauri.release.conf.json`, baked into every build, so the private half can never be
|
||||
rotated without stranding everyone who has not updated yet; back up the key and its password
|
||||
somewhere that is not the machine that generated them.
|
||||
|
||||
Beyond the signing key there is nothing to provision. Margin Docs talks to no external API and
|
||||
holds no OAuth client, unlike margin-calendar, so there are no other repository secrets and nothing
|
||||
That file currently carries the placeholder `REPLACE_WITH_TAURI_SIGNER_PUBKEY`, and the keypair
|
||||
behind it does not exist yet. Making it is a one-time step, run once by whoever owns the repository
|
||||
and never again:
|
||||
|
||||
```
|
||||
pnpm tauri signer generate -w ~/.tauri/margin-docs.key
|
||||
```
|
||||
|
||||
It asks for a password, writes the private key to that path and the public key beside it as
|
||||
`margin-docs.key.pub`, and prints both. The public one replaces the placeholder in
|
||||
`tauri.release.conf.json` and is committed. The private one is the contents of
|
||||
`~/.tauri/margin-docs.key`, pasted into `TAURI_SIGNING_PRIVATE_KEY`, with its password in
|
||||
`TAURI_SIGNING_PRIVATE_KEY_PASSWORD`. Neither the key file nor the password goes into the
|
||||
repository.
|
||||
|
||||
Six more secrets codesign and notarize the bundle, and unlike the two above they are optional as
|
||||
far as the workflow is concerned: with none of them set the build still runs, still publishes, and
|
||||
produces an ad hoc signed app. `APPLE_CERTIFICATE` is the Developer ID Application certificate
|
||||
exported from Keychain Access as a `.p12` and base64 encoded (`base64 -i certificate.p12`), with
|
||||
the password it was exported under in `APPLE_CERTIFICATE_PASSWORD`. `APPLE_SIGNING_IDENTITY` is the
|
||||
certificate's full name, which looks like `Developer ID Application: Your Name (TEAMID)`. The other
|
||||
three are for notarization: `APPLE_ID` is the Apple account's email address, `APPLE_PASSWORD` is an
|
||||
app-specific password made at appleid.apple.com rather than the account password itself, and
|
||||
`APPLE_TEAM_ID` is the ten character team identifier.
|
||||
|
||||
Those six are all or nothing. A repository with a certificate but no notarization credentials fails
|
||||
the build rather than warning, because a signed bundle that has not been notarized is one Gatekeeper
|
||||
refuses on any machine that has not seen it before, and finding that out from a user is worse than
|
||||
finding it out from a red run.
|
||||
|
||||
The bundle asks for the hardened runtime, which notarization requires, and for no entitlements at
|
||||
all. That is worth a sentence because it nearly went the other way. Deleting a document goes to the
|
||||
Trash through the `trash` crate, whose macOS default is to ask Finder over an Apple event, and the
|
||||
hardened runtime blocks an Apple event unless the bundle carries
|
||||
`com.apple.security.automation.apple-events` and the user agrees to a permission prompt about
|
||||
controlling Finder. `src-tauri/src/fs.rs` asks for `trashItemAtURL:` instead, which needs none of
|
||||
that. The cost is Put Back, which the Finder method leaves on the file and this one does not; the
|
||||
file is still in the Trash and can still be dragged out of it.
|
||||
|
||||
Beyond signing there is nothing to provision. Margin Docs talks to no external API and holds no
|
||||
OAuth client, unlike margin-calendar, so there are no other repository secrets and nothing
|
||||
equivalent to a `google-credentials.json` to embed at build time.
|
||||
|
||||
## Updates
|
||||
@@ -56,4 +97,21 @@ equivalent to a `google-credentials.json` to embed at build time.
|
||||
Installed copies check
|
||||
`https://github.com/priyanshujain/margin-docs/releases/latest/download/latest.json` and update
|
||||
themselves from it. `--latest` on the publish step is what moves that pointer, so a release that
|
||||
fails the manifest check stays a draft and no one is offered a broken update.
|
||||
fails the manifest check stays a draft and no one is offered a broken update. The app checks that
|
||||
URL once a day in the background and on the Check for Updates menu item, and either way what
|
||||
happens next is a dialog rather than an install: the version, the release notes, the download with
|
||||
a progress bar, and Later as a real answer.
|
||||
|
||||
Self-update does not work yet, and it will not until there is an Apple Developer ID certificate.
|
||||
This is not a gap in the workflow, which is wired for one, or in the app, which is wired for the
|
||||
whole flow. It is macOS: an update replaces the installed bundle with the downloaded one, and the
|
||||
system will not let an ad hoc signed bundle take the place of a signed one, nor run a replacement
|
||||
whose signature does not match what was there before. Every build this repository can currently
|
||||
produce is ad hoc signed, so every self-update attempt ends in a bundle the system refuses to
|
||||
launch. Until the certificate exists, updates are something to install by hand, and the honest
|
||||
version of the feature is that the app will find the update, show it, download it, and fail on the
|
||||
last step.
|
||||
|
||||
There is a second thing gated behind the same certificate. The build is not notarized either, so a
|
||||
copy downloaded from the releases page is quarantined by the browser and refused on first launch
|
||||
with the message about an unidentified developer. Both problems have the one fix.
|
||||
Reference in new issue
Block a user