docs: build-and-sign Mac App Store Tauri section, pitfall 114, changelog

This commit is contained in:
CRTkafa 2026-10-24 12:16:19 +08:00
parent f588f4e1aa
commit 33a7f73ab9
3 changed files with 54 additions and 0 deletions

View file

@ -8,6 +8,8 @@
- New `storebound shots copy translate --to de,es` fills store/shots/copy.json per language (agent translation or `--translate "<cmd>"`), machine-translated until `shots copy reviewed`, caption limits respected; `shots copy check`; `check` / `shots render` name this command for a missing language.
- `apple game-center --locale-map en=en-GB` (config `games.localeMap`) maps a config language to the live Game Center locale; the dry run suggests it when the live Game Center has exactly one variant of the language.
- `play games`: a 403 SERVICE_DISABLED / accessNotConfigured names the Google Play Game Services Publishing API, the enable URL for the project and `console plan play-games-services`.
- `apple build --platform macos --tauri <src-tauri> [--path-free] [--unsigned]`: Mac App Store build of a Tauri app. Generated sandbox entitlements, Mac App Store profile (installed, `--profile` or from the API), Apple Distribution / Mac Installer Distribution identities, `tauri build --bundles app`, checks of the .app, `productbuild` to a signed .pkg, `pkgutil --check-signature`; `--path-free` remaps local paths in rustc and fails on any leak of the home folder or user name. `apple upload <pkg> --platform macos` uploads it (platform MAC_OS). New certificate types MAC_APP_DISTRIBUTION and MAC_INSTALLER_DISTRIBUTION. Pitfall 119.
- Desktop dev update channel: Settings > Updates offers Stable (the npm releases) and Dev (every push to main). Each push to main builds Windows and Linux bundles stamped `<next patch>-dev.<UTC commit time>` (above the current stable, below the next one); the VDS signs them and serves `storebound.dev/desktop/dev/latest.json` (newest 5 kept). The app checks its channel at start, every 15 minutes, after sleep and right after a channel switch, installs a strictly newer build quietly (deferred while the window is in use), never downgrades (dev back to stable waits for a newer stable), rewrites its logon autostart on every start, and the tray card shows version and channel. No macOS dev builds (Developer ID signing needs the Mac's GUI session).
- `shots` full-bleed layout: `shots.layout: "bleed"` fills the image with the app's own frame (no device, no background) and puts the scene title as a short corner caption (`corner`, `captionScale`, `captionWidth`, `captionInset` per scene) legible through a text shadow and soft glow only; the Play feature graphic shows the logo or `shots.feature.title`. Frames are captured per size at its own pixels in `<frames>/<lang>/<size>/<name>.png` (feature: `<lang>/feature/`), including the `mac` and `chromebook` sizes; `shots check` / `capture --source folder` verify aspect and native width. `shots.orientation: "landscape"` (bleed only) renders every portrait size landscape (stores accept it). Templates `template-bleed.html`, `feature-bleed.html`.
- `storebound desktop`: "opened" now also works when a hidden tray copy is already running. On Windows it prints "opened" only when a process of the installed path has a visible window (the running copy shows it through the single-instance handoff); on macOS / Linux a visible start or a handoff to the running copy counts, otherwise it says only a tray copy runs. The graceful stop waits 3 s on Windows (closing a tray app only hides it), then stops by PID.

View file

@ -85,6 +85,32 @@ when the owner said so for this run). The MCP server offers only `apple_signing_
6. **Next.** `storebound apple encryption --build N`, `storebound apple testflight distribute --build N --group Team
--dry` (`testflight` skill), `storebound apple listing --version x.y.z --build N` (`appstore-first-release`).
## Mac App Store: a Tauri app (.pkg)
`storebound apple build --platform macos --tauri apps/desktop/src-tauri --path-free --dry` prints the plan; without
`--dry` it runs in the Mac's logged-in GUI session (not over SSH: write a .command file and `open -a Terminal` it):
1. Version from `--version` or tauri.conf.json, build number from `--build-number` or the next free one on App Store
Connect for macOS (CFBundleVersion must increase). `tauri.conf.json` `identifier` must equal `apple.bundleId`.
2. Identities from the login keychain: "Apple Distribution" (or "3rd Party Mac Developer Application") and "Mac
Installer Distribution" (or "3rd Party Mac Developer Installer"). The installer one is its own certificate type
(`apple.signing.certificateType: 'MAC_INSTALLER_DISTRIBUTION'`, `apple signing ensure`).
3. Provisioning profile: `--profile`, else an installed one, else the active `MAC_APP_STORE` profile from the API
(`apple.signing.profileType: 'MAC_APP_STORE'`).
4. `tauri build --bundles app --target universal-apple-darwin --config <overlay>`: the overlay sets the signing identity,
the generated entitlements (app sandbox, application / team identifier, your own keys kept), the embedded profile,
hardened runtime and `bundleVersion`. Set `bundle.category` and `bundle.macOS.minimumSystemVersion` in
tauri.conf.json (the build stops without LSApplicationCategoryType / LSMinimumSystemVersion).
5. Checks of the .app (sandbox, no get-task-allow, profile inside, version / build), `codesign --verify`, then
`productbuild --component <app> /Applications --sign <installer identity>` and `pkgutil --check-signature`.
6. `--path-free`: rustc remaps the checkout, CARGO_HOME, RUSTUP_HOME and the home folder, no debug info, symbols stripped;
the build fails when the home folder or user name is still in the app. `--unsigned` runs the pipeline without
identities (not uploadable). Result: `<out>/export/<version>-<build>/<Product>.pkg` (`--out`, default `build/macos`).
Then `storebound apple upload <pkg> --platform macos --dry` and without `--dry` (App Store Connect build upload,
platform MAC_OS, or `--via altool`). The .pkg is checked first (installer signature); the build shows up in the macOS
version's build list once processed. Details and fixes: `store-pitfalls` 119.
## Android
1. **Upload key.** Generate once (`keytool -genkeypair -v -storetype PKCS12 -keystore upload.p12 -alias upload

View file

@ -1415,3 +1415,29 @@ that fails without the fix (see CONTRIBUTING.md).
`storebound shots copy reviewed --lang de`. Captions over the limit (eyebrow 30, title line 28, sub 90, badge 18) are
not kept.
- **Guard:** `cli/shots/copy.ts`, `cli/lib/shots-copy-translate.ts`, `tests/shots-copy-translate.test.ts`.
## 119. A Tauri Mac App Store build was refused (no sandbox, no profile, wrong installer certificate) or carried the builder's home folder
- **What happens:** a plain `tauri build` makes a Developer ID app: no `com.apple.security.app-sandbox`, no
`embedded.provisionprofile`, signed with the wrong certificate, packed as a .dmg. Packed by hand into a .pkg it fails at
upload with ITMS-90xxx (sandbox, missing profile, CFBundleVersion not above the last one, no LSApplicationCategoryType) or
the .pkg is signed with an application certificate. Separately, rustc panic messages and debug info carry the
checkout, `~/.cargo` and the user name (`/Users/<name>/...`, hundreds of times in a release binary), which ends up
in a public download.
- **Do:** `storebound apple build --platform macos --tauri <src-tauri> --path-free --dry`, then the same without `--dry`
in the Mac's logged-in GUI session (codesign over SSH fails with errSecInternalComponent). It needs, on the Mac: an
"Apple Distribution" (or "3rd Party Mac Developer Application") and a "Mac Installer Distribution" (or "3rd Party Mac
Developer Installer") identity in the login keychain, and an active MAC_APP_STORE profile
(`apple.signing.profileType: 'MAC_APP_STORE'`, `apple signing ensure`, or `--profile <file>`). The installer certificate
is a separate certificate type (`MAC_INSTALLER_DISTRIBUTION`). `--unsigned` checks the whole pipeline without them
(never uploadable). A universal build needs both Rust targets (rustup); with Homebrew Rust only the host
target exists: pass `--target aarch64-apple-darwin`.
- **Guard:** `cli/lib/mas.ts` / `cli/apple/build-mas.ts`: entitlements generated with sandbox and application / team
identifier (the project's own keys kept), profile embedded through a tauri.conf overlay, bundleVersion from App Store
Connect (platform MAC_OS) so it increases, the built app checked (sandbox entitlement, no get-task-allow, category,
minimum OS, profile inside, version / build), `--path-free` remaps checkout / CARGO_HOME / RUSTUP_HOME / home in rustc,
drops debug info and symbols and fails when the home folder or user name is still in the app (without the flag the
same scan warns). `cargo trim-paths` is not used: it is nightly-only (cargo 1.98 refuses it). `apple upload <pkg>
--platform macos` refuses an unsigned .pkg or one not signed with an installer certificate before any network call
(`tests/mas-build.test.ts`). The `com.apple.pkg` file type of the API build upload is taken from Apple's schema and has not
been exercised against the live API yet; `--via altool` (`--type macos`) is the fallback.