On this page

Desktop publisher and Developer ID

Stado owns the repeatable path from a desktop repository to a signed macOS release. The publisher runner builds on a registry-selected Darwin host; Weles performs the Account Holder browser trajectory; Skarbiec holds credentials and the reusable certificate bundle; GitHub receives only repository-scoped release secrets.

Prepare a repository

stado host publisher-runner bootstrap <repository> --json

This creates or reuses the repository's Sparkle key pair and publishes RELEASE_BOOTSTRAP_TOKEN, AC_API_KEY_ID, AC_API_ISSUER_ID, AC_API_KEY_P8, and SPARKLE_PRIVATE_KEY. Repeating the command preserves the existing Sparkle identity.

Install or reconcile the publisher

stado host publisher-runner install <target> \
  --repository <repository> \
  --json

target must resolve through the Stado registry to darwin-arm64. Stado installs the isolated stado-publisher account and launchd unit, registers the runner in GitHub's Default group, applies the publisher network policy, and reuses an existing .runner registration instead of requesting a new organization token. Repeat --repository to bootstrap every desktop product in the same run.

Inspect it with:

stado host publisher-runner status <target> --json

A ready publisher reports a running service and a Developer ID Application: identity in its dedicated keychain.

Prepare Apple challenge capture

Prepare and inspect the registered Darwin host without beginning Apple account authorization. The workload capability replaced host gui-automation …, so preparation is one declared plan against one declared kind:

cat > apple-only.json <<'PLAN'
{"schema":"wisent.gui-automation-plan.v1","operation":"grant-accessibility","apple_only":true}
PLAN
stado workload run gui-automation --target <target> --plan apple-only.json --json
stado workload status gui-automation --target <target> --json

The preparation command installs or reuses the signed Apple challenge helper version 2, reconciles only its Accessibility grant, and runs its prompt-free --preflight in the registry-bound user's exact Aqua session. It supplies the registered host-account password to remote sudo -S over stdin rather than prompting; without one it uses noninteractive sudo -n and returns the refusal. apple_only leaves CuaDriver, its grants and runtime, autologin, and remote management untouched.

Both JSON reports preserve target, ssh_target, the ordered items pairs, and error. A successful preparation and subsequent status report include apple-challenge-ready: yes; a partial failure still returns completed items and its error, and must not be read as readiness.

This is helper preparation only. It does not request an Apple authorization, capture a code, issue a certificate, or prove that issuance ran. The Developer ID trajectory below is separately authorized and may require Apple sign-in, system consent, and Account Holder 2FA.

Issue or reuse Developer ID

The Account Holder credential must be a Skarbiec item named weles-apple-<name>-account, with email and password fields.

stado host publisher-runner developer-id <target> \
  --account-item weles-apple-<name>-account \
  --repository <repository> \
  --json

For the first run Stado:

  1. creates a private key and CSR on the selected Mac;
  2. issues three one-use, one-hour Skarbiec capabilities bound to one authorization ID: Apple email fill, password fill, and 2FA;
  3. asks Weles to run apple_create_developer_id on that exact host and agent;
  4. imports Apple's certificate, verifies the Developer ID Application: identity, and exports a password-protected PKCS#12 bundle;
  5. stores the bundle as desktop-release-developer-id in Skarbiec;
  6. publishes MACOS_CERT_P12, MACOS_CERT_PASSWORD, and MACOS_SIGN_IDENTITY to every named repository;
  7. removes private key material from the host work directory.

Later runs reuse the stored bundle and only reconcile repository secrets. They do not repeat Account Holder 2FA.

Trust boundaries

The GitHub runner never receives the Apple Account password. Weles receives short-lived capability references rather than credential plaintext in action parameters. The private key is generated on the Mac, enters Skarbiec only inside the encrypted PKCS#12 bundle, and is removed after storage succeeds. Repository secrets contain release signing material, not the Account Holder credential.

Failure readings

  • cannot issue ... release platform — the selected target is not darwin-arm64.
  • Skarbiec refused Apple capability — capability issuance or its authorization binding failed.
  • Weles API refused /run — the installed Weles action contract or placement policy does not admit apple_create_developer_id.
  • Developer ID bundle export failed — Apple did not produce the certificate, or the certificate does not match the generated private key.
  • GitHub repository secret ... failed — the certificate exists in Skarbiec, but the named repository has not received all signing fields.

The command is successful only when it returns status: issued or status: reused and names the Developer ID identity and every reconciled repository.

Source: this website