Reference
Issue one developer signing certificate, with the key kept on your machine.
weles developer-certificate --provider apple generates the key and certificate request locally, mints three one-use Apple capabilities on the execution host through Stado, starts apple_create_developer_id there, and writes the issued Developer ID Application certificate once the run finishes.
Why it exists#
Apple issues a Developer ID Application certificate only in its developer portal: the App Store Connect API answers 403 "This operation can only be performed by the Account Holder" for every API key. The portal needs a signed-in browser, which is Weles', so issuance is one authorized Weles run rather than a person clicking through the portal.
The command is named for what it issues. --provider names the certificate authority; apple is the one Weles implements, and a start without it is refused with exit 2.
Commands#
Start: weles developer-certificate --provider apple --subject <distinguished name> [--account-role <role>] --confirm "AUTHORIZE ONE APPLE DEVELOPER ID" --execution-host <stado-host> --private-key-out <absolute path> --expires-in-minutes <minutes> [--execution-agent weles-worker]. --subject is the certificate request's distinguished name and is always given, because it names your organization: no organization is built in. --expires-in-minutes is how long the one-use capabilities live, and is always given: Weles chooses no lifetime. The Apple account is asked for by its Skarbiec role, apple-account-holder unless --account-role names another; the worker selects the item tagged stado:role:<role> and refuses a role no item, or more than one item, plays. It writes a 2048-bit RSA key (mode 0600) to --private-key-out, derives the certificate request from it, asks Stado (stado identity issue-apple-capabilities) for the three one-use capabilities bound to a new guard id and the execution host, and starts apple_create_developer_id through the executor's POST /run with detached: true. The request travels in the run's params (it is public); the key never leaves this machine. The answer names the run, the guard id, the account role and the next command.
Read: weles developer-certificate --run <run-id> --certificate-out <absolute path> [--private-key <the --private-key-out path> --store-host <vault owner>]. The run id names the run, so reading needs no --provider. While the run is still going it answers status running. When it finished it takes the run result (GET /diagnostics/<run>/file?path=run-result.json), requires exactly one CERTIFICATE_BASE64 line holding a DER X.509 certificate (checked with openssl x509), checks the Apple 2FA receipt when Apple asked for one (source capability, provider accepted, holder, user and destination named), and writes the certificate (mode 0644).
With --private-key and --store-host (always both), read mode also packs the key and certificate into one PKCS#12 under a fresh random password (handed to openssl through its environment, not its arguments) and stores it in the vault of --store-host in the role macos-developer-id, with the fields certificate_p12_base64, certificate_password and sign_identity (the certificate's common name), through stado credentials item put --role. Stado rotates the item already playing that role or creates one under a random id tagged stado:role:macos-developer-id; no item is named. Those are the fields every darwin release recipe reads as MACOS_CERT_P12, MACOS_CERT_PASSWORD and MACOS_SIGN_IDENTITY through the role; the answer's stored names the role, host and identity.
Configure WELES_WORKER_API_BASE and WELES_WORKER_TOKEN as for account-security and app-password when the executor is not the one Stado's route names. Both modes print the answer as key: value lines, or as one JSON document with --json.
weles developer-certificate --provider apple --subject "/CN=<organization> Developer ID Application/O=<organization>/C=<country>" --confirm "AUTHORIZE ONE APPLE DEVELOPER ID" --execution-host <stado-host> --private-key-out ~/signing/developer-id.key --expires-in-minutes <minutes>
weles developer-certificate --run <returned-run-id> --certificate-out ~/signing/developer-id.cer --private-key ~/signing/developer-id.key --store-host <vault-owner-host>Refusals and diagnosis#
A start without --provider apple is refused with exit 2: "developer-certificate needs --provider naming the certificate authority; Weles issues through apple". --subject must be a distinguished name beginning /CN=; --account-role must be a Skarbiec role (lowercase letters, digits and hyphens); --confirm must equal the phrase exactly; --execution-host must name a Stado host; --expires-in-minutes is required ("--expires-in-minutes is required") and must be a positive whole number of minutes; --private-key-out and --certificate-out must be absolute and must not exist yet; --private-key and --store-host are refused one without the other, and --private-key must be an existing absolute path. Each is refused before anything is generated, issued or stored. On the worker, "no Skarbiec item carries stado:role:<role>" or "<n> Skarbiec items carry stado:role:<role>" refuses the run before a browser opens.
"stado credentials item put --role macos-developer-id on <host>: …" carries Stado's own refusal of the vault write, including two items already playing the role; "openssl pkcs12: …" means the key does not match the certificate or openssl could not pack them. The certificate file is written before either step; after a failed store, read the same run again with a new --certificate-out path, which needs no new Apple run.
"Stado did not issue Apple capabilities on the execution host": Stado refused the capability request; its own last line precedes it. submit_apple_create_developer_id / read_apple_run_result name the executor endpoint and its HTTP answer.
A finished run without a certificate answers ok: false with the run's error or stderr tail; the run itself prints FAIL=<reason>. "did not return exactly one certificate" and "invalid Apple 2FA receipt" mean the run result does not prove issuance; nothing is written.
Account sign-in#
weles login --provider apple [--account-role <role>] --confirm "AUTHORIZE ONE APPLE LOGIN" --execution-host <stado-host> --expires-in-minutes <minutes> [--execution-agent weles-worker] mints the same three one-use capabilities, living as many minutes as --expires-in-minutes says, for a new guard id and starts apple_login on the execution host through POST /run with detached: true; weles login --run <run-id> answers the run's status, ok and error. Both print key: value lines, or one JSON document with --json. A start without --provider apple is refused with exit 2; the other refusals are the same, and submit_apple_login names the executor answer.