mirror of
https://github.com/priyanshujain/margin.git
synced 2026-10-04 03:57:03 +00:00
some more fixes
This commit is contained in:
1 parent
7a3c04f170
commit
2b86a407ba
63 files changed
+12172
-44
No files matched your search
@@ -0,0 +1,106 @@
|
||||
# Distribution
|
||||
|
||||
Decided 2026-08-30 for Margin, Margin Calendar and Margin Docs. Margin Mail follows the same shape.
|
||||
|
||||
## Channels
|
||||
|
||||
All the apps are free. No licence gate, no in-app purchase, so Apple takes no cut and the App Store
|
||||
anti-steering rules do not apply.
|
||||
|
||||
The Mac App Store is the primary macOS channel: sandboxed, no self-updater, a separate build track.
|
||||
Direct download from margin.73ai.org stays the unrestricted build carrying the Tauri updater. macOS
|
||||
also ships through the user's own Homebrew tap, `priyanshujain/homebrew-margin`, rather than upstream
|
||||
homebrew-cask, which the repos do not clear the notability bar for.
|
||||
|
||||
Linux ships through a Nix flake. Do not propose the AUR again: the AUR job and PKGBUILD were removed
|
||||
on 2026-09-03 because the user has no AUR account and signups are restricted. The Nix package is a
|
||||
binary repackage of the released deb, for the same reason the AUR one was, which is that the Google
|
||||
OAuth client is embedded at compile time from a file that is not in the repo, so a from-source build
|
||||
by a stranger produces an app that cannot connect. The wrapper sets a `*_PACKAGED_BY=nix` variable so
|
||||
the in-app updater announces new versions without trying to install over the store.
|
||||
|
||||
Nix is not installed on the user's Mac. Test a flake through the amd64 `nixos/nix` Docker image with
|
||||
`filter-syscalls = false`, since seccomp fails under emulation, and a named volume on `/nix`.
|
||||
|
||||
No migration bridge was built for the library moving into the App Store sandbox container. There are
|
||||
effectively no existing users and a first-run import is not worth building yet.
|
||||
|
||||
## Licensing
|
||||
|
||||
Margin is FSL-1.1-MIT: free for anything except a competing product, becoming MIT two years after
|
||||
each release. Chosen because the user wants open code that nobody else monetises, which is not open
|
||||
source by the OSI definition. AGPL was ruled out because it is incompatible with the Mac App Store.
|
||||
Margin Mail is FSL-1.1-MIT too.
|
||||
|
||||
Margin Calendar and Margin Docs are still MIT and have not been relicensed. That is an open question,
|
||||
and consolidating shared code into one package forces it: shared code cannot be under two licences.
|
||||
|
||||
## The updater pubkey lives in an overlay
|
||||
|
||||
`plugins.updater.pubkey` and `bundle.createUpdaterArtifacts` live in `src-tauri/tauri.release.conf.json`,
|
||||
a release-only overlay merged with `--config` in the GitHub Actions release workflow. They are
|
||||
deliberately kept out of the committed `tauri.conf.json`.
|
||||
|
||||
The reason is a Tauri bug (tauri-apps/tauri#14581): the mere presence of `plugins.updater.pubkey` in
|
||||
`tauri.conf.json` makes `tauri build` demand a signing key, which breaks the local key-free build.
|
||||
The overlay scopes signing and updater artifacts to CI. Only CI-built signed releases need to
|
||||
self-update anyway.
|
||||
|
||||
The release workflow is a manual `workflow_dispatch` with prepare, a build matrix and publish. The
|
||||
matrix should be `max-parallel: 1`, because tauri-action merges `latest.json` read-modify-write
|
||||
across platforms and parallel jobs race.
|
||||
|
||||
It is not, in any app. Checked on 2026-09-06: `margin/.github/workflows/release.yml:91`,
|
||||
`margin-caledar/.../release.yml:85` and `margin-mail/.../release.yml:85` set `fail-fast: false` and
|
||||
nothing else, and Margin Docs has no matrix at all. The constraint was recorded once and then lost,
|
||||
which is exactly the failure this consolidation is for. The shared build job in
|
||||
[../release.md](../release.md) sets it.
|
||||
|
||||
## Signing
|
||||
|
||||
Signing keys and CSRs live in `~/.margin-signing`: Developer ID Application, Apple Distribution, the
|
||||
installer certificate and the App Store Connect key, each with a `.pass` file. They were generated
|
||||
with openssl rather than Keychain Access so CI `.p12` files can be rebuilt without a GUI. The
|
||||
Developer ID is in the login keychain and `codesign` uses it without prompting.
|
||||
|
||||
Never print the contents of anything in that directory.
|
||||
|
||||
## Google Cloud
|
||||
|
||||
One Cloud project, `margin-500217`, numeric id `205537985128`, owned by **[email protected]** and not by
|
||||
the Google account signed into the apps. Margin Calendar's desktop `google-credentials.json` is a
|
||||
copy of Margin's, so they share one OAuth desktop client, which means they share the consent screen
|
||||
and the enabled API list.
|
||||
|
||||
Enabling an API is per project, not per client. On 2026-08-10 the calendar scope was granted
|
||||
correctly and every `calendarList` call still returned 403 `SERVICE_DISABLED`, because the Calendar
|
||||
API had never been enabled on that project. A `gcloud services enable` run as the gmail account was
|
||||
denied, because that account does not own the project. If a Google resource comes back empty while
|
||||
auth succeeds, check the API is enabled before suspecting sync, and run the enable as pj@73ai.org.
|
||||
|
||||
Phones share the desktop client deliberately. A Desktop client may redirect to loopback on any port
|
||||
without registering it, and Google's token endpoint checks the client id, secret and redirect rather
|
||||
than the calling OS. Verified on 2026-08-12 on both an iOS simulator and an Android emulator. This
|
||||
works because the protocol does not check, not because Google blesses it; the fallback if they ever
|
||||
enforce it is a per-platform client, which the code already supports.
|
||||
|
||||
One thing still argues for a real iOS client: it switches iOS to `ASWebAuthenticationSession`, which
|
||||
shares Safari's session, so the user is not asked to sign in again. Android needs nothing, because
|
||||
Chrome Custom Tabs already share Chrome's cookies, which was measured rather than assumed. The iOS
|
||||
session sharing could not be confirmed on the simulator and needs a real device.
|
||||
|
||||
The client secret is not confidential for an installed app. Embed it, through the same release
|
||||
overlay pattern as the updater pubkey, so local builds stay clean.
|
||||
|
||||
Refresh tokens are not in any keychain. They are XChaCha20-Poly1305 sealed in a file under the app
|
||||
data directory, so the old `security find-generic-password` check no longer applies anywhere.
|
||||
|
||||
## Never touch cloud infrastructure unasked
|
||||
|
||||
Reading is fine: list, describe, get, dry runs. Changing is not. Do not create, delete, rename or
|
||||
reconfigure a project, bucket, database, service, key, credential, IAM binding or DNS record, do not
|
||||
enable or disable an API, and do not attach billing without being asked for that exact thing on that
|
||||
exact resource. Permission does not carry forward to the next request.
|
||||
|
||||
If something turns out to be blocked, say it is blocked and why. Do not route around it. A workaround
|
||||
that provisions new infrastructure is a much bigger decision than the one that was made.
|
||||
Reference in new issue
Block a user