diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9c166d7..d0cfb65 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,41 +31,10 @@ jobs: RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} run: | if [ -z "$RELEASE_TOKEN" ]; then - echo "::error::RELEASE_TOKEN secret is not set. Releases need a personal access token with repo scope on both jonhadfield/certreader and jonhadfield/homebrew-certreader, because the darwin build pushes the cask update to the tap and the built-in GITHUB_TOKEN cannot write to another repository." + echo "::error::RELEASE_TOKEN secret is not set. Releases need a personal access token with repo scope on both jonhadfield/certreader and jonhadfield/homebrew-certreader, because the darwin build pushes the formula update to the tap and the built-in GITHUB_TOKEN cannot write to another repository." exit 1 fi echo "RELEASE_TOKEN is configured" - - - # Signing is optional: what makes a homebrew install run is shipping a - # formula rather than a cask, since a cask quarantines what it installs. - # Half-configured is worth saying out loud though, because goreleaser - # silently skips signing when the certificate is absent. - name: check macos signing credentials - env: - MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }} - MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }} - MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }} - MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }} - MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }} - run: | - missing="" - present="" - for name in MACOS_SIGN_P12 MACOS_SIGN_PASSWORD MACOS_NOTARY_ISSUER_ID MACOS_NOTARY_KEY_ID MACOS_NOTARY_KEY; do - value="${!name}" - if [ -z "$value" ]; then - missing="$missing $name" - else - present="$present $name" - fi - done - if [ -z "$present" ]; then - echo "the darwin binaries will not be signed, which is supported: see the release section of the README" - elif [ -n "$missing" ]; then - echo "::error::macos signing is half configured, missing:$missing. goreleaser skips signing entirely when the certificate is absent, so set all five or none of them." - exit 1 - else - echo "macos signing credentials are configured" - fi - name: install goreleaser uses: goreleaser/goreleaser-action@v6 @@ -179,13 +148,6 @@ jobs: run: make ${{ matrix.target }} env: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} - # only the darwin target signs, so only that job is given the - # credentials to do it with - MACOS_SIGN_P12: ${{ matrix.target == 'release-mac' && secrets.MACOS_SIGN_P12 || '' }} - MACOS_SIGN_PASSWORD: ${{ matrix.target == 'release-mac' && secrets.MACOS_SIGN_PASSWORD || '' }} - MACOS_NOTARY_ISSUER_ID: ${{ matrix.target == 'release-mac' && secrets.MACOS_NOTARY_ISSUER_ID || '' }} - MACOS_NOTARY_KEY_ID: ${{ matrix.target == 'release-mac' && secrets.MACOS_NOTARY_KEY_ID || '' }} - MACOS_NOTARY_KEY: ${{ matrix.target == 'release-mac' && secrets.MACOS_NOTARY_KEY || '' }} - # the linux and windows targets build as root inside the container, so # the archives come back owned by root and unreadable to the next step diff --git a/.goreleaser/.goreleaser.darwin.yml b/.goreleaser/.goreleaser.darwin.yml index 4fba759..cb4d792 100644 --- a/.goreleaser/.goreleaser.darwin.yml +++ b/.goreleaser/.goreleaser.darwin.yml @@ -34,30 +34,6 @@ archives: formats: - tar.gz -# Signing the binaries with a Developer ID certificate, for anyone who would -# rather have it than not. It is off unless the certificate is configured, and -# it is not what makes a homebrew install run: a bare binary has nowhere to -# staple a notarization ticket, and on macos 26 an unstapled ticket did not -# satisfy gatekeeper for a quarantined binary in testing. What fixes that is the -# brews block below, by not being quarantined in the first place. -notarize: - macos: - - enabled: '{{ isEnvSet "MACOS_SIGN_P12" }}' - ids: - - darwin-arm64 - - darwin-amd64 - sign: - certificate: "{{ .Env.MACOS_SIGN_P12 }}" - password: "{{ .Env.MACOS_SIGN_PASSWORD }}" - notarize: - issuer_id: "{{ .Env.MACOS_NOTARY_ISSUER_ID }}" - key_id: "{{ .Env.MACOS_NOTARY_KEY_ID }}" - key: "{{ .Env.MACOS_NOTARY_KEY }}" - # the archives are uploaded from this same run, so the binaries they - # carry must be signed and accepted before it moves on - wait: true - timeout: 20m - checksum: name_template: "checksums_darwin.txt" diff --git a/README.md b/README.md index 4ca2097..3cf56ef 100644 --- a/README.md +++ b/README.md @@ -614,18 +614,18 @@ fixtures on every test run. Releases are built and published with [GoReleaser](https://goreleaser.com) from a tagged commit. Pushing the tag is all that is needed — the `release` workflow builds every platform and uploads the -artifacts to a single GitHub release, then updates the homebrew cask. +artifacts to a single GitHub release, then updates the homebrew formula. ```shell script git tag -a -m "add super cool feature" v1.0.0 git push --follow-tags ``` -### required secrets +### required secret Platform builds run in parallel, so a release takes about as long as its slowest target rather than the sum of all five. A prerelease tag (one containing a hyphen, such as `v1.0.0-rc1`) is published as -a prerelease and does not update the homebrew cask. +a prerelease and does not update the homebrew formula. Release notes come from the annotated tag message, so write the tag with the notes you want. @@ -633,28 +633,9 @@ The workflow needs a `RELEASE_TOKEN` repository secret: a personal access token both `jonhadfield/certreader` and `jonhadfield/homebrew-certreader`. The token built into Actions cannot write to another repository, and the darwin build pushes the formula update to the tap. -Signing the darwin binaries is optional, and off unless all five of these are set. It is not what -makes an install work — the formula is, see [why a formula and not a cask](#why-a-formula-and-not-a-cask) -— so treat it as something to have rather than something to fix: +Without it the workflow stops at its preflight job and publishes nothing. -| secret | what it is | -| --- | --- | -| `MACOS_SIGN_P12` | base64 of the Developer ID Application certificate, exported as `.p12` | -| `MACOS_SIGN_PASSWORD` | the password that `.p12` was exported with | -| `MACOS_NOTARY_KEY` | base64 of an App Store Connect `.p8` key | -| `MACOS_NOTARY_KEY_ID` | that key's id, also in its filename | -| `MACOS_NOTARY_ISSUER_ID` | the issuer uuid shown when the key was created | - -```shell script -gh secret set MACOS_SIGN_P12 --repo jonhadfield/certreader < <(base64 -i DeveloperID.p12) -gh secret set MACOS_NOTARY_KEY --repo jonhadfield/certreader < <(base64 -i AuthKey_XXXXXXXXXX.p8) -``` - -Without `RELEASE_TOKEN` the workflow stops at its preflight job and publishes nothing. The signing -secrets are all-or-nothing: GoReleaser skips signing entirely when the certificate is absent, so -preflight fails a half-configured set rather than letting it publish quietly unsigned. - -Run the workflow manually from the Actions tab to check the secrets and the GoReleaser configs +Run the workflow manually from the Actions tab to check the secret and the GoReleaser configs without cutting a tag; a manual run stops after preflight. ### why a formula and not a cask @@ -670,8 +651,9 @@ $ echo $? ``` A bare executable has nowhere to keep a ticket — `stapler` needs an app bundle, a disk image or an -installer package — so signing and notarizing the binary does not settle it. On macOS 26 a notarized -but unstapled binary was still refused in testing. +installer package — so signing and notarizing the binary does not settle it. On macOS 26.5 a binary +signed with a Developer ID certificate and accepted by the notary service was still refused under +quarantine, on every attempt within ten minutes of the ticket being issued. A **formula** is not quarantined, which is how every other Go command line tool in Homebrew arrives able to run. GoReleaser calls `brews` deprecated in favour of `homebrew_casks`; the cask is what