mirror of
https://github.com/rudrankriyam/App-Store-Connect-CLI.git
synced 2026-04-25 07:35:48 +03:00
[GH-ISSUE #431] Feature: macOS Notarization via Notary REST API #123
Labels
No labels
bug
bug
documentation
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/App-Store-Connect-CLI#123
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @rudrankriyam on GitHub (Feb 6, 2026).
Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/431
Overview
Add support for macOS notarization using Apple's Notary REST API. This enables developers to submit, track, and inspect notarization requests directly from
asc— without requiring macOS, Xcode, orxcrun notarytool.The Notary API is a separate REST API from the main App Store Connect API, but uses the same JWT authentication and API keys. It lives at
https://appstoreconnect.apple.com/notary/v2/(not in the App Store Connect OpenAPI spec).Why This Matters
xcrun notarytool, gon) shells out to Apple's native CLI, requiring macOS + Xcode. The only pure REST API implementation isbep/macosnotarylib(Go library, no CLI).asc authcan notarize immediately. Same key, same issuer, same JWT.--output table/markdown,--paginate— same patterns as every otherasccommand.Use Case
A developer distributes a macOS app outside the Mac App Store with Developer ID and needs to notarize it:
API Documentation
Scope (Notary API endpoints)
The Notary API has 4 endpoints, all at
https://appstoreconnect.apple.com/notary/v2/:POST/submissionsGET/submissionsGET/submissions/{id}GET/submissions/{id}/logsNote: This API is NOT in the App Store Connect OpenAPI spec (
docs/openapi/latest.json). It is documented separately by Apple.Submission Workflow
Apple's notarization uses a two-step upload process. The Notary API does not accept the file directly — instead, it returns temporary cloud storage credentials so you can upload the file to Apple's storage, and Apple picks it up from there for scanning.
/submissionswith{ submissionName, sha256, notifications? }— returns temporary AWS S3 credentials (awsAccessKeyId,awsSecretAccessKey,awsSessionToken,bucket,object) and a submissionid/submissions/{id}to poll status — returnsAccepted,In Progress,Invalid, orRejected/submissions/{id}/logsto retrieve a signed URL to the JSON log fileThe temporary upload credentials expire after 12 hours. If not used before expiry, the submission must be restarted.
Authentication
Identical to App Store Connect API:
ASC_KEY_ID,ASC_ISSUER_ID, private key)Authorization: Bearer <token>Proposed CLI
Command group
Subcommands
asc notarize submitSubmit a file for notarization, upload it, and optionally wait for completion.
Flags:
--file: path to.zip,.dmg, or.pkg--wait: block until notarization completes (poll status)--webhook: URL to receive notification on completion--output,--pretty: standard output flagsBehavior:
/submissionswith file name, hash, and optional webhook--wait, poll/submissions/{id}until terminal stateasc notarize statusCheck the status of a submission.
Flags:
--id: submission ID (required)--wait: poll until terminal state--output,--prettyasc notarize logGet the notarization log for a submission.
Flags:
--id: submission ID (required)--download: save log to file instead of printing URL--output,--prettyasc notarize historyList recent notarization submissions.
Flags:
--output,--prettyasc notarize staple(optional, macOS only)Staple the notarization ticket to a package. This shells out to
xcrun stapler staplesince stapling is not available via the REST API.Flags:
--file: path to.dmg,.pkg, or.appFlag Patterns
Common:
--id,--output,--prettyNew:
--wait,--webhook,--file,--downloadOutput
--prettyfor pretty-printed JSON--output table/markdownfor human-readable outputSubmit output example:
Status output example:
Detailed TODO
Core
NotaryBaseURL = "https://appstoreconnect.apple.com/notary/v2")internal/asc/client_notarize.goSubmitNotarization(ctx, name, sha256, webhookURL) (*NotarySubmissionResponse, error)GetNotarizationStatus(ctx, submissionID) (*NotarySubmission, error)GetNotarizationLog(ctx, submissionID) (*NotaryLogResponse, error)GetNotarizationHistory(ctx) (*NotaryHistoryResponse, error)internal/asc/notarize.goNotarySubmissionRequest,NotarySubmissionResponseNotarySubmission,NotaryLogResponse,NotaryHistoryResponseNotaryUploadCredentials)internal/asc/notarize_upload.goCLI
internal/cli/notarize/packagenotarize.go—NotarizeCommand()group with subcommandssubmit.go— submit + upload + optional waitstatus.go— check submission statuslog.go— retrieve notarization loghistory.go— list previous submissionsstaple.go— optional macOS-only staple wrappershared_wrappers.go— standard shared wrapperscommands.go—Command()factoryinternal/cli/registry/registry.goUsageFunc: shared.DefaultUsageFuncon all commandsOutput
internal/asc/notarize_output.goTests
--id, missing file path, invalid file)--waitpolling test (status transitions: In Progress → Accepted)--waitpolling test (status transitions: In Progress → Rejected)internal/cli/cmdtest/Acceptance Criteria
asc notarize submit ./file.zipsubmits and uploads via the REST API (no xcrun dependency)asc notarize submit --waitpolls until completion and prints final statusasc notarize status --id IDreturns current submission statusasc notarize log --id IDreturns log URL or downloads logasc notarize historylists recent submissionsasc authcredentials — no additional auth setup--output table/markdownsupportedDependencies
The file upload step requires uploading to an AWS S3 bucket using temporary credentials provided by Apple. Two approaches:
github.com/aws/aws-sdk-go-v2/service/s3) — handles multipart upload, retries, and transfer acceleration cleanly, but adds a heavier dependencynet/httpwith S3's REST interface directly (likebep/macosnotarylibdoes), keeping dependencies minimalEvaluate both approaches. The minimal approach aligns better with the project's "standard library first" philosophy from
docs/GO_STANDARDS.md.Implementation Notes
appstoreconnect.apple.com/notary/v2vsapi.appstoreconnect.apple.com/v1)internal/authtoken generation.zip,.dmg,.pkgxcrun stapler stapleon macOSbep/macosnotarylibGo library (MIT, single file) is a useful reference implementation--waitpolling, use exponential backoff starting at ~5s, capping at ~30sPrior Art
xcrun notarytoolxcrun notarytoolbep/macosnotarylibasc notarizeReferences
bep/macosnotarylib: https://github.com/bep/macosnotarylib (Go reference implementation)internal/auth/(JWT generation — reusable as-is)internal/asc/client_core.go(BaseURL, HTTP helpers)@rudrankriyam commented on GitHub (Feb 6, 2026):
Implemented in PR #432 and released in 0.25.0.