Troupe Cloud
Signing credentials
A signing credential is what a store build signs with: an App Store Connect API key for iOS, an upload keystore for Android. This page covers the kinds of credential, who may sign with one, managing them, and how a build uses them.
The model below is built and is what the service will offer. Until then, an Android store or
deviceInternal build takes "signing": "none" and its output is not signed with a credential, and an iOS
store build, which is signed as it is built, cannot run. Simulator and emulator builds need no credential.
Kinds of credential
| Kind | What you give | What Troupe does with it |
|---|---|---|
ascApiKey | An App Store Connect API key: its .p8 file, key id and issuer id | Asks Apple for a distribution certificate and an App Store profile for each bundle id a build signs |
androidUploadKeystore | Nothing: Troupe generates one (PKCS12, RSA 4096, valid 10,000 days). Or your own PKCS12 or JKS keystore of at most 64 KiB, with its passwords and key alias | Signs AABs and APKs with the upload key |
iosDistributionIdentity | Nothing: Troupe makes it with your App Store Connect key | Holds the distribution certificate and the profiles; its parentId names the key it came from |
A secret goes in once and never comes back out. Every read returns metadata only: the kind, the name, key and team ids, the certificate's serial, digests, subject and validity, the profiles' ids, and the allow-lists. For an Android upload keystore the metadata includes the upload certificate as PEM, which is what you register with Google Play.
Who may sign
A credential carries its own allow-lists. A build is signed only when all three agree.
| List | Meaning |
|---|---|
projects | The projects whose builds may sign: up to 64 of them, or "all". Only an owner may set "all", and only while the organization's placement is org |
sourceRefs | Up to 16 rules, each a repository URL and up to 16 ref patterns. A build signs only from a listed repository at a matching ref |
allowTarballs | Whether builds of an uploaded tarball may sign. Off by default: a tarball's origin cannot be checked |
A ref pattern is a full ref, such as refs/heads/main or refs/tags/v1.2.0, or a prefix ending in *, such
as refs/tags/v*. A build of the branch main matches refs/heads/main. A build of a commit id matches no
pattern, so build a branch or a tag when you sign. The repository is compared as builds normalize their source
URL: https://host/owner/repo, lower-case host, no trailing slash.
The caller needs signing:use, which owners and admins hold and an API key may carry.
Manage credentials
Owners and admins manage credentials on the organization's Signing page. Every change needs a password confirmation, so none can be made with an API key.
| On the page | Procedure |
|---|---|
| Upload an App Store Connect key | credentials.uploadAscKey |
| Generate an Android upload keystore | credentials.createAndroidKeystore |
| Upload an Android upload keystore | credentials.uploadAndroidKeystore |
| Show the upload certificate | credentials.get |
| Rotate | credentials.rotate |
| Change who may sign | credentials.updateAllowList |
| Delete | credentials.delete |
A key file is read in the page and sent once; delete your download afterwards.
Rotating replaces the secret and keeps the credential's id and allow-lists; its version goes up by one.
After rotating an App Store Connect key, revoke the old key at Apple. Before rotating an Android upload key,
have Google accept the new one (an upload key reset in the Play Console), or Play refuses builds signed with
it.
Deleting removes the secret and keeps the metadata, marked deleted. Builds that name the credential then
fail to sign. An iOS identity's certificate at Apple is not revoked. After a rotation or a deletion, a backup
taken earlier still holds the old secret, encrypted, until that backup expires.
How a build uses one
A store or deviceInternal build names its credential in signing on
builds.create. The credential must be active, of the kind the
platform needs, and must allow the build's project, repository and ref.
| Build | Credential | What happens |
|---|---|---|
iOS store | ascApiKey | The build receives a single-use signing bundle, archives and exports an .ipa signed for App Store Connect, and checks every signed bundle |
Android store | androidUploadKeystore | Gradle builds the AAB with no signing configuration; Troupe then signs it with the upload key |
Android deviceInternal | androidUploadKeystore | The same, for an APK |
The Android keystore never enters the build machine. A signed artifact's metadata names the credential, the
signing certificate's SHA-256 and the signature schemes; an unsigned one says "none".
What builds.create answers when a signing request cannot stand:
| Answer | When |
|---|---|
VALIDATION (required) | A store or deviceInternal build names no signing, or an iOS store build names "none" |
VALIDATION (not-signed) | A simulator or emulator build names a credential |
FORBIDDEN | The caller lacks signing:use |
NOT_FOUND | The credential does not exist, is deleted, or does not allow this project |
CONFLICT (credential-kind-mismatch) | An Android build names an App Store Connect key, or the other way round |
CONFLICT (signing-not-allowed) | The repository, the ref or the tarball is not on the credential's list |
The allow-lists are checked again when the output is signed. A build refused then ends with the failure reason
signing-refused.