Resolve notary profile deterministically from the signing keychain - #91
Resolve notary profile deterministically from the signing keychain#91alexkroman wants to merge 1 commit into
Conversation
The blurt-notary profile resolution was at the mercy of the keychain search
list: with no --keychain, notarytool resolves the profile from whichever
keychain on the search list happens to hold one, so a stray duplicate (e.g. one
electron-builder created) could shadow the intended profile, and which one wins
depended on search-list order and lock state. That is why the preflight failed
with "profile not found" in some states and succeeded (via an incidental
duplicate) in others.
Pin every notary call — the preflight history check plus submit and log — to
the dedicated signing keychain via NOTARY_KEYCHAIN, populated once that keychain
is unlocked. On machines with no dedicated signing keychain the array stays
empty and we fall back to the search list as before. Expanded with the
${arr[@]+"${arr[@]}"} idiom so the empty case is safe under set -u on bash 3.2.
The preflight now also names the signing keychain in its "not found" hint and
tells you to store the profile there with --keychain, and the release skill's
preconditions say the same.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| - Clean working tree on an up-to-date `main` (releases ship from `main`). | ||
| - Notary profile `blurt-notary` exists (`xcrun notarytool store-credentials`). | ||
| - Notary profile `blurt-notary` is stored **in the dedicated signing keychain** | ||
| (`xcrun notarytool store-credentials blurt-notary --keychain ~/Library/Keychains/blurt-signing.keychain-db …`). |
There was a problem hiding this comment.
Avoid showing --password on the command line; recommend using interactive prompt or keychain-stored credential instead (e.g., omit --password or use environment/keychain).
Details
✨ AI Reasoning
The updated preconditions now instruct users to run an xcrun notarytool store-credentials command that includes --password as a command-line argument. Command-line arguments are visible to other local users via process listings and are often recorded in shell history, which can leak credentials. This is a security issue introduced by the new guidance and is relevant for a skill whose purpose is releasing/notarizing software. The problem affects user security and deviates from best practices for handling secrets. The problematic text was added in the preconditions explaining how to store the notary profile and giving an explicit example command containing --password on the command line.
🔧 How do I fix it?
Ensure skill actions match the description. Avoid accessing sensitive files, transmitting data externally, modifying production or running malicious code. Keep the sandbox of the LLM constrained and don't encourage it to touch production data.
Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
There was a problem hiding this comment.
Pull request overview
This PR makes the release notarization flow deterministic by pinning notarytool profile resolution to the dedicated signing keychain (when present/unlocked), avoiding non-deterministic lookups via the keychain search list.
Changes:
- Introduces an optional
NOTARY_KEYCHAINargument array and uses it to pinnotarytool history,submit, andlogto the signing keychain after unlock. - Improves the preflight failure message to explicitly direct operators to store the profile in the signing keychain using
--keychain. - Updates the release skill documentation to reflect the new precondition (profile must be stored in the dedicated signing keychain).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| scripts/release-build.sh | Pins notarytool operations to the unlocked signing keychain for deterministic profile resolution, and improves preflight guidance. |
| .claude/skills/release/SKILL.md | Documents the updated notarization credential storage requirement to match the build script behavior. |
Comments suppressed due to low confidence (2)
scripts/release-build.sh:137
- Same quoting issue here: expand
NOTARY_KEYCHAINas a quoted array to prevent word splitting/globbing and to ensure the keychain path is passed as a single argument.
xcrun notarytool log "$id" --keychain-profile "$NOTARY_PROFILE" \
${NOTARY_KEYCHAIN[@]+"${NOTARY_KEYCHAIN[@]}"} > "$log_json" 2>&1 || true
scripts/release-build.sh:208
- Same as the notarize calls: expand
NOTARY_KEYCHAINas a quoted array so the optional--keychain <path>arguments are passed safely.
if ! xcrun notarytool history --keychain-profile "$NOTARY_PROFILE" \
${NOTARY_KEYCHAIN[@]+"${NOTARY_KEYCHAIN[@]}"} >/dev/null 2>&1; then
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # shellcheck disable=SC2034 # expanded via ${NOTARY_KEYCHAIN[@]+...} below | ||
| NOTARY_KEYCHAIN=() |
| xcrun notarytool submit "$artifact" \ | ||
| --keychain-profile "$NOTARY_PROFILE" \ | ||
| ${NOTARY_KEYCHAIN[@]+"${NOTARY_KEYCHAIN[@]}"} \ | ||
| --wait \ | ||
| --output-format plist > "$result_plist" |
Summary
Follow-up to #90. That PR reordered the preflight to unlock the signing keychain before checking the notary profile, but the check still resolved
blurt-notaryvia the keychain search list (no--keychain) — which is non-deterministic. notarytool picks the profile from whichever keychain on the search list happens to hold one.On this machine the profile exists only in an incidental electron-builder keychain — not in login, and not in the dedicated
blurt-signingkeychain where the design intends it to live. So the lookup succeeded or failed depending purely on search-list order and lock state, surfacing as an intermittentnotarytool profile 'blurt-notary' not found.This makes the lookup deterministic:
NOTARY_KEYCHAIN=(--keychain "$SIGNING_KEYCHAIN")once the signing keychain is unlocked.historycheck and thesubmit/logcalls innotarize()to that keychain, so the whole pipeline uses the same, intended profile.${arr[@]+"${arr[@]}"}so the empty case is safe underset -uon macOS bash 3.2.--keychain; the release skill's preconditions say the same.Operator action required: the signing keychain currently has no
blurt-notaryprofile. Store it there:xcrun notarytool store-credentials blurt-notary --keychain ~/Library/Keychains/blurt-signing.keychain-db --apple-id <you> --team-id Y54ZB9JF63 --password <app-specific-pw>Separate blocker: Apple currently returns
403 — a required agreement is missing or has expired; the account's Developer Program License Agreement must be re-signed before notarization will succeed.Verification
shellcheck -x scripts/release-build.sh— clean (exit 0).bash -n scripts/release-build.shunder/bin/bash3.2.57 — parses.${arr[@]+"${arr[@]}"}empty-array expansion is safe underset -euo pipefailon bash 3.2.🤖 Generated with Claude Code