diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43b9b05..4656ee3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -129,7 +129,7 @@ jobs: cp target/aarch64-apple-darwin/release/kit stage/kit if [[ $SIGN_RELEASE == true ]]; then codesign --force --options runtime --timestamp \ - --identifier com.danielkov.kit \ + --identifier com.speakeasy.kit \ --sign "$MACOS_SIGNING_IDENTITY" stage/kit codesign --verify --strict --verbose=2 stage/kit ditto -c -k --keepParent stage/kit "$RUNNER_TEMP/kit-notarization.zip" diff --git a/Cargo.lock b/Cargo.lock index cf3f112..debafab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2517,7 +2517,7 @@ dependencies = [ [[package]] name = "kit" -version = "0.1.97" +version = "0.1.98" dependencies = [ "a2a-protocol-client", "a2a-protocol-server", diff --git a/Cargo.toml b/Cargo.toml index 191ff98..ca4d33a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kit" -version = "0.1.97" +version = "0.1.98" edition = "2024" rust-version = "1.94.0" publish = false diff --git a/README.md b/README.md index 42e0184..da3f103 100644 --- a/README.md +++ b/README.md @@ -558,7 +558,7 @@ target/release/kit tui --mcp-config mcp.json \ On macOS, `.cargo/config.toml` routes `cargo run` through a runner that signs the fresh debug binary before executing it. Set `KIT_CODESIGN_IDENTITY`, or put the certificate name in the gitignored `.kit-codesign-identity` file. Both paths use -the stable identifier `com.danielkov.kit`, overridable with +the stable identifier `com.speakeasy.kit`, overridable with `KIT_CODESIGN_IDENTIFIER`. A changed identity, a missing certificate, or a locked Keychain may prompt again. `cargo install` does not run the runner; sign its installed binary separately. Apple Development diff --git a/docs/releasing.md b/docs/releasing.md index 8cf781e..19556c8 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -20,25 +20,55 @@ Clippy, and tests, builds Linux x86-64 and macOS arm64 archives, generates checksums, and publishes them to the tagged GitHub release. Prerelease tags are marked as prereleases on GitHub. -## Optional macOS signing and notarization +## macOS signing and notarization -The macOS build does not require Apple credentials. When none are configured, -the workflow publishes an unsigned, unnotarized archive and identifies it as -such in the release notes. This is the expected setup until signing credentials -are added to the repository. +The release workflow signs the standalone Mach-O executable with the code-signing +identifier `com.speakeasy.kit`, enables the hardened runtime, and submits it to +Apple's notary service. This Developer ID distribution does not require an Apple +App ID or provisioning profile. -To enable signing and notarization, configure all of these repository secrets: +Create the credentials as follows: -- `MACOS_CERTIFICATE_P12_BASE64` -- `MACOS_CERTIFICATE_PASSWORD` -- `MACOS_SIGNING_IDENTITY` -- `APPLE_API_KEY_P8_BASE64` -- `APPLE_API_KEY_ID` -- `APPLE_API_ISSUER_ID` +1. In Keychain Access, use **Certificate Assistant > Request a Certificate From + a Certificate Authority** to save a certificate signing request (CSR). +2. In Apple Developer **Certificates, Identifiers & Profiles**, create a + **Developer ID Application** certificate from that CSR. If that option is not + available for your role, ask the team's Account Holder to create it. Import + the downloaded certificate on the Mac that created the CSR. +3. In Keychain Access, export the Developer ID certificate together with its + private key as a password-protected PKCS#12 (`.p12`) file. Record the exact + identity shown by `security find-identity -v -p codesigning`. It normally has + the form `Developer ID Application: ()`. +4. In App Store Connect **Users and Access > Integrations**, create a team API + key that can access the notary service. Record its key ID and issuer ID, and + retain the downloaded `.p8`; Apple does not allow it to be downloaded again. +5. Store the `.p12`, its password, and the `.p8` in the company's secret manager. + Configure these repository Actions secrets: + + - `MACOS_CERTIFICATE_P12_BASE64`: base64-encoded `.p12` + - `MACOS_CERTIFICATE_PASSWORD`: `.p12` export password + - `MACOS_SIGNING_IDENTITY`: exact Keychain identity from step 3 + - `APPLE_API_KEY_P8_BASE64`: base64-encoded `.p8` + - `APPLE_API_KEY_ID`: App Store Connect API key ID + - `APPLE_API_ISSUER_ID`: App Store Connect issuer ID + +For example, from a trusted Mac authenticated to GitHub CLI: + +```sh +repo=speakeasy-api/kit +base64 < DeveloperIDApplication.p12 | gh secret set MACOS_CERTIFICATE_P12_BASE64 -R "$repo" +read -r -s 'p12_password?P12 password: '; echo +printf %s "$p12_password" | gh secret set MACOS_CERTIFICATE_PASSWORD -R "$repo" +unset p12_password +printf %s 'Developer ID Application: Example Corp (TEAMID)' | gh secret set MACOS_SIGNING_IDENTITY -R "$repo" +base64 < AuthKey_KEYID.p8 | gh secret set APPLE_API_KEY_P8_BASE64 -R "$repo" +printf %s 'KEYID' | gh secret set APPLE_API_KEY_ID -R "$repo" +printf %s 'issuer-uuid' | gh secret set APPLE_API_ISSUER_ID -R "$repo" +``` The workflow fails on a partial configuration rather than silently publishing -an unsigned build. Downloaded `.p8` keys cannot be downloaded again, so retain -the original in the company's secret manager. +an unsigned build. With none of these secrets configured, it still publishes an +unsigned, unnotarized archive and identifies it as such in the release notes. ## Verify a release diff --git a/scripts/codesign-runner.sh b/scripts/codesign-runner.sh index 8456016..b81f578 100755 --- a/scripts/codesign-runner.sh +++ b/scripts/codesign-runner.sh @@ -12,7 +12,7 @@ if [ "$(basename "$binary")" = kit ]; then if [ -z "$identity" ] && [ -r "$root/.kit-codesign-identity" ]; then IFS= read -r identity < "$root/.kit-codesign-identity" fi - identifier="${KIT_CODESIGN_IDENTIFIER:-com.danielkov.kit}" + identifier="${KIT_CODESIGN_IDENTIFIER:-com.speakeasy.kit}" if [ -n "$identity" ] && security find-identity -v -p codesigning 2>/dev/null | grep -Fq "\"$identity\""; then codesign --force --options runtime --identifier "$identifier" --sign "$identity" "$binary" else diff --git a/scripts/notarize-release.sh b/scripts/notarize-release.sh index 2d5e736..a38a84e 100755 --- a/scripts/notarize-release.sh +++ b/scripts/notarize-release.sh @@ -9,13 +9,13 @@ Builds, Developer ID signs, and notarizes the macOS ARM64 release binary on this Mac. The exact signed binary is preserved under dist/notarize/vVERSION/. Required configuration (`.env` or environment variables): + KIT_CODESIGN_IDENTITY KIT_NOTARY_API_KEY_DOCUMENT KIT_NOTARY_API_KEY_VAULT KIT_NOTARY_API_KEY_ID KIT_NOTARY_API_ISSUER_ID Optional overrides: - KIT_CODESIGN_IDENTITY KIT_CODESIGN_IDENTIFIER EOF } @@ -57,8 +57,8 @@ if [[ -n $(git status --porcelain) ]]; then exit 1 fi -identity=${KIT_CODESIGN_IDENTITY:-Developer ID Application: Inlucent Limited (TAMRUK8SL6)} -identifier=${KIT_CODESIGN_IDENTIFIER:-com.danielkov.kit} +identity=${KIT_CODESIGN_IDENTITY:?KIT_CODESIGN_IDENTITY must be set} +identifier=${KIT_CODESIGN_IDENTIFIER:-com.speakeasy.kit} api_key_document=${KIT_NOTARY_API_KEY_DOCUMENT:?KIT_NOTARY_API_KEY_DOCUMENT must be set} api_key_vault=${KIT_NOTARY_API_KEY_VAULT:?KIT_NOTARY_API_KEY_VAULT must be set} api_key_id=${KIT_NOTARY_API_KEY_ID:?KIT_NOTARY_API_KEY_ID must be set} @@ -88,7 +88,7 @@ umask 077 tmp_dir=$(mktemp -d "${TMPDIR:-/tmp}/kit-notary.XXXXXX") trap 'rm -rf "$tmp_dir"' EXIT api_key="$tmp_dir/AuthKey_${api_key_id}.p8" -op document get "$api_key_document" --vault "$api_key_vault" --output "$api_key" >/dev/null +op document get "$api_key_document" --vault "$api_key_vault" --out-file "$api_key" >/dev/null chmod 600 "$api_key" source_dir="$tmp_dir/source" mkdir -p "$source_dir" diff --git a/scripts/sign-release.sh b/scripts/sign-release.sh index ab48c50..ee0e774 100755 --- a/scripts/sign-release.sh +++ b/scripts/sign-release.sh @@ -7,7 +7,7 @@ if [ -z "$KIT_CODESIGN_IDENTITY" ] && [ -r "$root/.kit-codesign-identity" ]; the IFS= read -r KIT_CODESIGN_IDENTITY < "$root/.kit-codesign-identity" fi : "${KIT_CODESIGN_IDENTITY:?set KIT_CODESIGN_IDENTITY or create .kit-codesign-identity}" -KIT_CODESIGN_IDENTIFIER="${KIT_CODESIGN_IDENTIFIER:-com.danielkov.kit}" +KIT_CODESIGN_IDENTIFIER="${KIT_CODESIGN_IDENTIFIER:-com.speakeasy.kit}" if [ "$(uname -s)" != Darwin ]; then echo "codesigning is only supported on macOS" >&2