Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,17 @@ fallback for a non-git checkout.

## Releases go through the broker

Distributable, signed and notarized builds are meant to come from
`trsdn/macos-notarization-broker`, the same as sibling apps in this account.
As of this writing the broker's `openpromptr` profile is proposed but not yet
merged (trsdn/macos-notarization-broker#49, tracked in issue #7) — there is
no automated release path yet. `build-app.sh` is a local convenience for
development builds, signed with whatever identity is available locally
(falling back to ad-hoc with a warning); the broker assembles the app bundle
itself via its own `assemble_openpromptr` build step, so `build-app.sh` is
not necessarily the definition of what a broker-built release bundle looks
like — keep the two in sync deliberately, not by assumption, if one changes
(bundle layout, Info.plist location, resource bundles).
Distributable, signed and notarized builds come from
`trsdn/macos-notarization-broker` (profile `openpromptr`), the same as
sibling apps in this account. See `RELEASE_CHECKLIST.md` for the actual
per-release steps. No release has been cut yet (tracked in issue #7).
`build-app.sh` is a local convenience for development builds, signed with
whatever identity is available locally (falling back to ad-hoc with a
warning); the broker assembles the app bundle itself via its own
`assemble_openpromptr` build step, so `build-app.sh` is not necessarily the
definition of what a broker-built release bundle looks like — keep the two
in sync deliberately, not by assumption, if one changes (bundle layout,
Info.plist location, resource bundles).

## Architecture

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ Only Developer ID-signed releases from this project's own signing identity are
accepted; nothing else can be installed this way. Until a signed release
exists (tracked in
[issue #7](https://github.com/trsdn/OpenPromptr/issues/7)), a check simply
finds nothing to install.
finds nothing to install. See [RELEASE_CHECKLIST.md](RELEASE_CHECKLIST.md)
for how a release is actually cut and published.

## Limitations

Expand Down
117 changes: 117 additions & 0 deletions RELEASE_CHECKLIST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Release checklist

Distributable, signed and notarized builds of OpenPromptr are produced by
[`trsdn/macos-notarization-broker`](https://github.com/trsdn/macos-notarization-broker)
(profile `openpromptr`), not by this repository.

## Why the broker owns the release

Apple credentials never reach this repository. The broker treats application
repositories as untrusted: it builds the app from a pinned commit in a job
with no secrets, validates and repackages the result on a second secretless
runner, and only then signs and notarizes with broker-owned code in a
protected environment.

The practical consequence is that **this repository does not define the
release bundle**. `build-app.sh` exists for local development and testing
only; the broker assembles the bundle itself with its own
`assemble_openpromptr` build step. If the two ever disagree, the broker's
preflight rejects the release rather than signing something unexpected.

That also means a change to the bundle — identifier, executable name,
layout, architecture, entitlements, or minimum macOS version — is not a
local decision. It requires a reviewed pull request against the broker's
`profiles/apps.json`, and the release fails until that lands.

## Per release

1. Update `CHANGELOG.md`: move entries out of *Unreleased* into a new
version heading, with the date.
2. **Do not hand-bump the version.** Unlike some sibling apps,
`Config/Info.plist`'s `CFBundleShortVersionString`/`CFBundleVersion` are
only the fallback for a non-git checkout — both `build-app.sh` (local
builds) and the broker's `assemble_openpromptr` (release builds) derive
the real version from the git tag and stamp it into the built bundle. The
tag is the source of truth; editing the plist by hand does nothing for a
release.
3. `swift build && swift test` — must be clean. `swift format lint --strict
--recursive Sources Tests Package.swift` — must be clean; CI enforces
both, but check locally first.
4. `./build-app.sh` and run the result. At minimum, the
[optional runtime self-test](README.md#optional-runtime-self-test) if the
app already holds Screen Recording permission; otherwise a manual check —
pick each source type in turn, start output, and confirm the physical
target display shows the mirrored/rotated image correctly.
5. Merge to `main`, then tag `v<version>` and push the tag.
6. Request the notarized build from a checkout of the broker:

```bash
scripts/request.sh openpromptr v<version> --publish
```

The broker verifies the pinned commit and the reviewed dependency lock,
builds with `assemble_openpromptr`, and produces the artifacts declared
in the `openpromptr` profile: `OpenPromptr-v<version>-macOS-arm64.zip`,
`OpenPromptr-v<version>-macOS-arm64.dmg`, and
`OpenPromptr-<version>.dmg` — the last one is a copy of the DMG under the
exact filename [AppUpdater](https://github.com/mxcl/AppUpdater) requires
to find it. `--publish` uploads all three to the GitHub release for the
tag.
7. Write the GitHub release notes from the `CHANGELOG.md` entry for this
version (the broker does not generate them automatically — this is a
manual step for now).

## Local testing

```bash
./build-app.sh
```

Signed with whatever identity is on this machine (falling back to ad-hoc,
with a warning, if none is found), and not notarized. Good enough for
testing on this machine; publishing an ad-hoc or non-notarized build would
give users a Gatekeeper block on first launch.

## Verifying what you are about to publish

Notarization is easy to *believe* has happened, so check the broker's
artifact explicitly rather than trusting that a script printed something:

```bash
xcrun stapler validate OpenPromptr-v<version>-macOS-arm64.dmg
spctl --assess --type open --context context:primary-signature --verbose=2 \
OpenPromptr-v<version>-macOS-arm64.dmg
shasum -a 256 -c OpenPromptr-v<version>-macOS-arm64.dmg.sha256
```

Then mount it, drag the app to `/Applications`, and confirm on a machine
that has never run it that it starts without a Gatekeeper warning.

## Testing the updater

Existing installs of the pre-rename *Teleprompter Mirror* have no updater at
all and will never auto-update to OpenPromptr — see
[Upgrading from Teleprompter Mirror](README.md#upgrading-from-teleprompter-mirror)
in the README. Every OpenPromptr release from the first one onward carries
the updater, but there is nothing for it to find until a **second** release
exists. After cutting the second release:

1. Install the first release.
2. Launch it and use **Check for Updates…** (status menu or the app's
Update menu). It should find the second release, download it, and offer
**Install Update `<version>` and Restart…**.
3. Confirm installing actually replaces the app and relaunches it at the
new version (`OpenPromptr --version` or the About panel).
4. Confirm the install is refused with an explanatory alert if attempted
while output is running or recovering (`AppModel.canStop`) — start
output first, then try installing, to check this deliberately rather
than by accident.

## After a rename

The bundle identifier is part of every TCC grant. If it ever changes again,
old grants for the previous identifier stay behind in System Settings under
Privacy & Security, pointing at an app that no longer exists. Remove them
so users are not asked to trust two entries for one app. The broker's
profile pins the identifier, so a rename also needs a reviewed profile
change.