Skip to content

Code Signing Overview

RunnerHub supports two code signing modes for iOS and macOS apps:

  1. Automatic (recommended) — RunnerHub manages certificates and provisioning profiles using your Apple API key
  2. Manual — You upload your own P12 certificate and provisioning profiles

Both modes handle certificate installation, keychain management, and cleanup automatically. Choose the mode that works best for your workflow.

RunnerHub uses a two-level configuration model:

  1. Workspace Level: Apple App Store Connect API key + certificate setup
  2. App Level: Bundle ID and signing type configuration

When your job runs, RunnerHub automatically:

  • Generates a certificate signing request (CSR)
  • Creates or reuses Apple Distribution certificates
  • Fetches provisioning profiles from Apple
  • Installs everything in an isolated, ephemeral keychain
  • Injects signing environment variables into your build
  • Cleans up all signing artifacts after the job completes

In manual mode, you upload your own P12 certificate(s) and provisioning profiles to RunnerHub:

  1. App Level: Upload one or more P12 certificates and provisioning profiles
  2. During Build: RunnerHub installs all your uploaded certificates and profiles into an ephemeral keychain
  3. Automatic Selection: xcodebuild automatically picks the correct certificate based on the provisioning profile
  4. Environment: Signing environment variables are injected (same as automatic mode)
  5. Cleanup: All artifacts are cleaned up after the job

Manual mode supports multiple certificates per app — for example, you can upload both a development certificate and a distribution certificate. All certificates are installed into the build keychain, and xcodebuild automatically selects the correct one based on your provisioning profile.

Manual mode is useful if you want to:

  • Use existing certificates you already manage
  • Upload multiple certificates for different signing purposes (development, distribution, etc.)
  • Have specific signing requirements your workflow depends on
  • Avoid sharing Apple API credentials with RunnerHub

All signing operations happen in an ephemeral keychain—a temporary keychain that exists only for the duration of your job. This keychain:

  • Is created fresh for each job
  • Never touches your Mac’s login.keychain-db
  • Is encrypted and secured with a random password
  • Is automatically destroyed after the job finishes

This approach ensures:

  • Complete isolation between jobs
  • No persistent signing credentials on the build machine
  • Safe multi-tenant operation
  • Guaranteed cleanup

All sensitive credentials are encrypted at rest in the RunnerHub database:

  • Apple API keys
  • Certificate private keys
  • Provisioning profiles

Keys are decrypted only in memory when executing a job and never exposed in logs or artifacts.

You don’t need Fastlane Match or any other credential management tool. RunnerHub manages everything through the Apple API. If you already use Fastlane, it works seamlessly with RunnerHub’s signing setup.

RunnerHub supports code signing on all plans:

PlanManual Signing (iOS/macOS)Automatic Signing (iOS/macOS)Android Signing
FreeAvailableNot availableAvailable
PAYGAvailableAvailableAvailable
ProAvailableAvailableAvailable
BusinessAvailableAvailableAvailable

Manual Signing (Free+) — Upload your own P12 certificates and provisioning profiles. Requires no integration with Apple’s systems.

Automatic Signing (PAYG+) — Let RunnerHub manage certificates and profiles using your Apple API key. Automated certificate and profile creation, renewal, and lifecycle management.

Android Signing (Free+) — Upload your keystore directly on the app for APK/AAB signing. Available on all plans with no additional setup required.

RunnerHub supports multiple Apple credentials per workspace, allowing each app to select which credential to use.

Step 1: Add Apple Credentials (Workspace Level)

Section titled “Step 1: Add Apple Credentials (Workspace Level)”

Go to your workspace settings and add one or more Apple App Store Connect API keys. Each credential:

  • Gives RunnerHub permission to create certificates and fetch provisioning profiles
  • Has a display name (e.g., “Team A”, “Personal Account”) for easy identification
  • Can be used by any app in your workspace

See API Key Setup for detailed instructions.

Step 2: Configure Per-App Signing (App Level)

Section titled “Step 2: Configure Per-App Signing (App Level)”

For each app in your workspace, specify:

  • Bundle ID: Your app’s unique identifier (e.g., com.example.myapp)
  • Signing Type: How your app should be signed (development, adhoc, appstore, or developer-id for macOS outside-App-Store distribution)
  • Signing Mode: Select Automatic to use workspace credentials
  • Apple Credential: Select which credential from your workspace to use (required for automatic mode)

See Per-App Signing Configuration for details.

When a job runs with automatic signing enabled:

  1. RunnerHub fetches the selected API key and app configuration
  2. Sets up the ephemeral keychain with your certificate
  3. Injects signing environment variables (e.g., DEVELOPMENT_TEAM, PROVISIONING_PROFILE_SPECIFIER)
  4. Patches your Xcode project for manual signing
  5. Your build uses the configured signing credentials automatically

From your local machine:

  1. Open Keychain Access
  2. Find your Apple Distribution or Development certificate
  3. Right-click → Export
  4. Choose Personal Information Exchange (.p12) format
  5. Set a strong password
  6. Save the file

Step 2: Upload P12 and Provisioning Profiles

Section titled “Step 2: Upload P12 and Provisioning Profiles”

In the RunnerHub dashboard:

  1. Go to App SettingsCode Signing
  2. Select Manual as the signing mode
  3. Click Upload Certificate
  4. Select your .p12 file and enter the password
  5. Click Add Provisioning Profile and upload each .mobileprovision file
  6. Verify your bundle ID matches the profiles

When a job runs with manual signing enabled:

  1. RunnerHub sets up the ephemeral keychain with your uploaded certificate
  2. Installs your provisioning profiles
  3. Injects the same signing environment variables as automatic mode
  4. Your build uses the uploaded credentials automatically

Android signing is configured directly on each app and supports APK/AAB signing with your keystore.

You’ll need your Android keystore file (.jks or .keystore) and its passwords. If you don’t have one, you can:

  1. Use Android Studio’s Key Store Manager to generate one, or
  2. Use the command-line tool: keytool -genkey -v -keystore my-keystore.jks ...

In the RunnerHub dashboard:

  1. Go to App SettingsCode Signing
  2. Click Upload Android Keystore
  3. Select your .jks/.keystore file
  4. Enter the keystore password
  5. Enter the key alias (the name of the key within the keystore)
  6. Enter the key password (may be the same as the keystore password)
  7. Click Save

RunnerHub encrypts and stores your keystore securely. The file is never displayed in logs or artifacts.

In your runnerhub.yml, reference the keystore via environment variables:

- name: Build APK
run: |
./gradlew assembleRelease \
-Pandroid.injected.signing.store.file=$ANDROID_KEYSTORE_PATH \
-Pandroid.injected.signing.store.password=$ANDROID_KEYSTORE_PASSWORD \
-Pandroid.injected.signing.key.alias=$ANDROID_KEY_ALIAS \
-Pandroid.injected.signing.key.password=$ANDROID_KEY_PASSWORD

Or configure it in your build.gradle:

signingConfigs {
release {
storeFile file(System.getenv('ANDROID_KEYSTORE_PATH'))
storePassword System.getenv('ANDROID_KEYSTORE_PASSWORD')
keyAlias System.getenv('ANDROID_KEY_ALIAS')
keyPassword System.getenv('ANDROID_KEY_PASSWORD')
}
}

When you upload a keystore, RunnerHub automatically injects these variables:

Terminal window
ANDROID_KEYSTORE_PATH=/path/to/keystore/file.jks
ANDROID_KEYSTORE_PASSWORD=<your-keystore-password>
ANDROID_KEY_ALIAS=<your-key-alias>
ANDROID_KEY_PASSWORD=<your-key-password>

These variables are available throughout your job and can be used by Gradle, custom scripts, or any build tool.

  • iOS — Development, ad-hoc, and App Store signing (manual and automatic modes)
  • macOS — Development and App Store signing (manual and automatic modes)
  • Android — Upload keystore for signing (configured per-app, available on all plans)
  • Flutter — iOS/macOS signing via Automatic/Manual modes, Android signing via per-app keystore
  • React Native — iOS/macOS signing via Automatic/Manual modes, Android signing via per-app keystore (configure both when building for both platforms)

Signing is tied to your app’s platform configuration. For Flutter and React Native apps, configure both Apple and Android signing in the same Code Signing tab if you’re building for both platforms.

RunnerHub injects signing environment variables into your pipeline steps. Both automatic and manual modes inject the same set of variables.

Terminal window
CODE_SIGN_STYLE=Manual
DEVELOPMENT_TEAM=<your-team-id>
PROVISIONING_PROFILE=<profile-uuid>
RH_PROVISIONING_PROFILE_UUID=<profile-uuid>
RH_PROVISIONING_PROFILE_NAME=<profile-name>
RH_KEYCHAIN_PATH=<ephemeral-keychain-path>
OTHER_CODE_SIGN_FLAGS=--keychain <ephemeral-keychain-path>
RH_EXPORT_OPTIONS_PLIST=<path-to-plist>
Terminal window
APP_STORE_CONNECT_API_KEY_PATH=<path-to-p8-key>
APP_STORE_CONNECT_API_KEY_KEY_ID=<key-id>
APP_STORE_CONNECT_API_KEY_ISSUER_ID=<issuer-id>
APPLE_TEAM_ID=<your-team-id>

These variables are available to your pipeline steps, Xcode, Fastlane, and any scripts.

When auto-sign is enabled, RunnerHub automatically generates an ExportOptions.plist file in the workspace root (if one doesn’t already exist). This plist file contains all the necessary export options for building and exporting IPAs:

  • method: Maps to your signing type (app-store-connect for appstore, ad-hoc for adhoc, development for development)
  • teamID: Your Apple Team ID
  • signingStyle: Always manual (RunnerHub handles signing)
  • provisioningProfiles: Maps bundle ID to provisioning profile UUID

The file is exposed via the RH_EXPORT_OPTIONS_PLIST environment variable, which you can use directly in your export commands:

Terminal window
xcodebuild -exportArchive \
-archivePath $PWD/build/MyApp.xcarchive \
-exportPath $PWD/build \
-exportOptionsPlist $RH_EXPORT_OPTIONS_PLIST

When is the plist generated?

  • Only when auto-sign is enabled for your app
  • Only when both the provisioning profile name and bundle identifier are available
  • Only if no existing ExportOptions.plist exists in the repository root (your existing plist takes precedence)

This approach allows you to use your own custom plist if needed, while still providing RunnerHub-generated one for convenience when you want it.

FeatureAutomaticManual
Certificate ManagementRunnerHub creates/manages via Apple APIYou upload your own P12
Profile ManagementRunnerHub creates/manages via Apple APIYou upload .mobileprovision files
Apple API RequiredYesNo
Best ForMost users, automated certificate handlingExisting certificate workflows
Setup ComplexityModerate (add API key, configure app)Moderate (export cert, upload files)
Profile Expiry HandlingAutomatic renewalManual renewal required

For more details, see Certificates & Profiles.

Note on Android Signing: Android signing is configured per-app by uploading your keystore directly. No workspace-level setup is required. See Android Signing Setup above for details.

RunnerHub’s signing implementation is designed for secure multi-tenant operation:

  • Per-job isolation: Each job gets its own ephemeral keychain
  • No credentials persist: All signing artifacts are deleted after the job
  • Workspace isolation: One workspace cannot access another’s credentials
  • Encrypted storage: All credentials are encrypted at rest
  • Masked logs: Sensitive values are redacted in job logs

See Code Signing Troubleshooting if you encounter issues.