A macOS Runner step executes Bash directly on the host, not inside an automatically isolated disposable environment, according to Atlassian's macOS Runner documentation. That single fact changes the production decision: Bitbucket Pipelines macOS Runner is suitable for production only when you use trusted, dedicated nodes, enforce label routing, prove cleanup and signing isolation, and release capacity in stages.
A runner showing as connected proves connectivity. It does not prove that the previous job left the Mac clean, that a repository can reach only its intended node, or that a reboot will restore unattended service.
Who should read this
You are preparing Bitbucket Pipelines for iOS builds or releases and need a production acceptance standard.
You operate self-hosted Mac nodes and need evidence for isolation, credentials, recovery, and capacity.
You are a technical director or procurement owner comparing fixed Mac infrastructure with remote Mac build capacity.
01 The production gate starts with host trust
A failed build may be the visible symptom of a host contamination problem. A previous script can write outside the checkout, install a global tool, alter a shared cache, create a launch process, modify a keychain, or leave a process listening on a local port. The next job may then consume that state without showing an obvious cause in its own logs.
This risk is higher when one node serves unrelated repositories. It is also higher when external pull requests and production signing jobs share the same host. A cleanup script can remove known files. It cannot reliably turn a previously modified host into a fresh trust boundary.
Use this acceptance rule:
- If every workload on a node belongs to the same trust domain, the node may be considered for a controlled shared pool.
- If a job can contain untrusted code, use a separate node pool.
- If a job can sign or publish software, use a higher-trust pool with separate credentials.
- If you cannot prove cleanup, do not route production work to that node.
- If recovery requires a person to log in and repair the Mac, classify the node as manual-operation capacity rather than unattended production capacity.
The relevant evidence is not a screenshot of the runner status. It is a record of what changed before the job, what the job changed, what remained afterward, and what the next clean build observed.
Operational warning: A green runner status is a control-plane signal. It is not evidence of filesystem isolation, keychain isolation, or build reproducibility.
02 Workspace hygiene is a measurable acceptance metric
Start with a deliberately dirty test. The test job should attempt the same classes of side effect that a real pipeline can create:
- Write inside and outside the checkout.
- Add a file to a global tool location.
- Create a temporary service or background process.
- Populate dependency and compiler caches.
- Generate derived data and archives.
- Import a temporary signing identity.
- Export a credential to an environment variable.
- Cancel the job during each sensitive phase.
Do not test only whether the checkout directory disappears. Inspect the host after the job:
- Source checkout and generated files.
- Xcode derived data.
- Dependency-manager caches.
- Temporary files.
- Archives and exported packages.
- Running processes.
- Launch agents or persistent services.
- Keychain identities and profiles.
- Environment variables visible to the next task.
- Logs and artifacts retained by the pipeline.
Separate automatic platform behavior from team-owned behavior. The Bitbucket Runner management guidance helps you verify registration and runner administration. It does not replace a host-level inspection of files, processes, services, or keychains created by your scripts.
A useful acceptance record has four columns: the action attempted, the expected residue, the observed residue, and the disposition. “No residue found” is not sufficient if the inspection scope is not stated.
For untrusted repositories, external contributions, and release signing, the safest control is node separation. Use cleanup as a secondary control. Do not use one cleanup script as a substitute for isolation.
03 Runner scope and labels define the routing boundary
Bitbucket provides Repository Runners and Workspace Runners. Their authorization radius differs. A Repository Runner is tied to a narrower repository context. A Workspace Runner can serve repositories within the relevant workspace scope. Read the current Bitbucket Runner registration documentation before selecting the scope.
A broader scope is not automatically wrong. It is wrong when the team treats it as private while multiple repositories can target it. Workspace scope requires an explicit trust decision, ownership model, credential policy, and review process.
Labels are the routing control. In the pipeline definition, the runs-on labels should express workload intent, not merely operating system. For example:
runs-on:
- self.hosted
- macos
- ios-release
Use labels such as ios-test, ios-archive, and ios-release only when each label maps to a reviewed node pool. The official YAML routing reference explains how labels connect a step to eligible runners.
Run these routing tests before production approval:
- Replace a required label with an incorrect label and confirm the task does not run on a higher-trust node.
- Send a job while the intended pool is busy and inspect queue behavior.
- Remove the matching label from a test node and confirm the job does not silently fall back.
- Attempt routing from a repository that should not access a Workspace Runner.
- Review the job log and runner log for the selected host identity.
- Confirm that test, archive, and signing labels cannot overlap accidentally.
A label is only useful if the node inventory behind it is stable. Document each label's trust level, macOS baseline, Xcode baseline, credential class, maintenance owner, and permitted repositories.
04 Bitbucket Pipelines macOS Runner needs a reproducible toolchain
The build host should have an approved baseline for macOS, Xcode, SDKs, package tools, shell behavior, and the service account. The exact Xcode release must be selected from the deployment-day support requirements and recorded with the acceptance evidence. Do not infer compatibility from the processor name alone.
Apple's Xcode command-line tool reference is the source for command-line tooling behavior. Use it to define the commands your build actually depends on. Keep the host configuration under change control, including selected developer directory, installed SDKs, package-manager state, and certificate profile.
Run reproducibility checks with the same commit:
- Build once on a clean approved node.
- Remove generated output and relevant temporary state.
- Build again without changing the commit.
- Compare dependency resolution, derived data behavior, archive metadata, and exported artifacts.
- Repeat on another node in the same pool.
- Record any expected nondeterministic fields separately from unexpected differences.
Caches need explicit ownership. A cache that improves speed but can be modified by unrelated repositories becomes a cross-job input. Use scoped cache keys and assume cached content is untrusted until validated. If a cache cannot be separated by repository or trust level, disable it for the sensitive job and measure the capacity impact.
Do not copy a Linux or generic cloud pipeline into macOS without reviewing shell commands, filesystem paths, keychain behavior, signing tools, GUI assumptions, and runner feature limits. The pipeline may parse correctly while failing operationally.
05 Signing and code access require separate evidence
An iOS release job has a different security profile from a unit-test job. Keep these items separate:
- Runner registration credentials.
- Source-control access credentials.
- Apple signing certificates.
- Provisioning profiles.
- App Store or release permissions.
- Cache contents.
- Build archives.
- Deployment tokens.
Store secrets through the supported Bitbucket variable and secret mechanisms rather than committing them to the repository or placing them in a shared script. The Bitbucket variables and secrets documentation defines the supported management model.
For Apple signing, use TN3161's certificate guidance and Apple's distribution signing documentation to document certificate handling and signing boundaries. The documentation does not remove the need for local verification.
Your evidence should show:
- Where a certificate enters the job.
- Which account and keychain can use it.
- Whether the private key is exportable.
- When the profile and certificate are removed.
- Whether a canceled job leaves signing material behind.
- Whether a test repository can read the release pool's keychain.
- Whether logs expose tokens, paths, certificate names, or sensitive variables.
- How rotation and emergency revocation are performed.
- Who approved the last credential change.
A release node should not share a keychain with a lower-trust test pool. It should not retain an archive merely because a later deployment step might need it. Transfer artifacts through an approved, access-controlled mechanism and define retention separately from the build host.
06 Recovery and queue behavior determine usable capacity
Test failure modes that operators often skip:
- Runner process exit.
- Runner disconnect.
- Mac reboot.
- Network interruption.
- Job cancellation.
- Host disk pressure.
- A job that leaves a child process running.
- A queue that exceeds the available worker capacity.
For each test, record the trigger, the expected state, the observed logs, whether the runner reconnected without manual login, whether it accepted a new task, and whether cleanup completed. A node that returns online but accepts a contaminated workspace is not recovered.
The Atlassian concurrency and queue reference should be used to inspect queue state and configured concurrency. Do not estimate capacity from developer headcount or advertised processor performance. Measure the workload that matters: clean build duration, archive duration, signing duration, peak queue depth, retry rate, and the effect of cache misses.
A simple capacity model is:
required worker capacity = peak concurrent demand + failure or maintenance reserve
Treat that as a planning relationship, not as a vendor performance claim. Your inputs must come from pipeline history or a controlled load test. If the queue grows during a normal release window, add capacity or reduce workload concurrency before declaring the pool production-ready.
07 Use staged admission instead of a single launch decision
Apply the following decision branches:
- If host-side writes are blocked or proven removable, credentials are isolated, and the node passes clean reruns, select the node for a limited trusted workload. Otherwise, move it to a disposable test pool and remediate.
- If Repository scope matches the ownership boundary, select it for a single-project pool. Otherwise, use Workspace scope only after repository access and trust relationships are documented.
- If every production step has an unambiguous label and no fallback route, select the pool for archive or release testing. Otherwise, keep release labels disabled.
- If reboot, process exit, network interruption, and cancellation tests recover without manual intervention, select the node for unattended operation. Otherwise, classify it as assisted capacity.
- If queue evidence covers the expected peak and maintenance reserve, select the planned pool size. Otherwise, run a longer load test or procure additional capacity.
- If all evidence is auditable, begin with a pilot, then limited production, then formal release. Otherwise, return the node to remediation.
Use the following tables as an acceptance tool, not as a substitute for test evidence.
| Production metric | Required evidence | Pass condition | Failure action |
|---|---|---|---|
| Host isolation | Filesystem, process, service, cache, and keychain inspection | No unapproved residue after a dirty-job test | Remove the node from shared production routing |
| Scope control | Repository or Workspace ownership record | Access matches the documented trust boundary | Narrow scope or split the pool |
| Label routing | Positive and negative runs-on tests |
Jobs reach only eligible labels | Disable the affected label |
| Toolchain repeatability | Same-commit clean rebuild records | Differences are explained and accepted | Freeze the baseline and investigate |
| Signing security | Import, use, cleanup, rotation, and revocation evidence | No cross-pool credential access | Revoke and rebuild the signing setup |
| Recovery | Process, reboot, network, and cancellation tests | Unattended return and clean new-job acceptance | Classify as non-production capacity |
| Queue capacity | Real pipeline duration and queue records | Peak demand remains within planned reserve | Add capacity or reduce concurrency |
| Workload | Suitable node scope | Credential level | Recommended routing |
|---|---|---|---|
| Unit tests from trusted repositories | Repository or carefully governed Workspace | No release signing | Dedicated test label |
| External contribution validation | Isolated Repository pool | No production credentials | Restricted validation label |
| Internal archive builds | Repository pool or trusted Workspace pool | Limited signing access | Archive label |
| Production iOS release | Dedicated Repository pool where possible | Release signing and publishing access | Release label with explicit approval |
| Deployment artifact handling | Dedicated controlled host or approved transfer path | Deployment credential access | Separate deployment step and audit trail |
| Acceptance result | Routing decision | Next action |
|---|---|---|
| Pilot pass | Non-production or internal trusted jobs | Observe logs, cleanup, and queue behavior |
| Limited production pass | Selected archive or release jobs | Increase workload gradually |
| Full evidence pass | Approved production pool | Set ownership, review cadence, and rotation schedule |
| Any critical failure | No production routing | Remediate, retest, and reopen the gate |
08 FAQ
How do you configure a macOS Runner for Bitbucket Pipelines?
Register the host in the intended Repository or Workspace scope, install the current runner software from the official Bitbucket instructions, and apply deliberate labels. Then bind the required labels under runs-on in bitbucket-pipelines.yml. Validate registration, routing, logs, workspace cleanup, and failure recovery before allowing production jobs.
Can a Bitbucket macOS Runner handle iOS release builds?
Yes, it can support iOS archive and release workflows when the host has an approved macOS and Xcode baseline, a controlled signing setup, and the required Apple credentials. Treat release signing as a higher-trust workload. Route it to a dedicated pool and verify that certificates, provisioning data, logs, and artifacts cannot cross workload boundaries.
How should Workspace Runners separate different repositories?
A Workspace Runner has a wider authorization radius than a Repository Runner because multiple repositories in that workspace may be able to target it. Use Workspace scope only when the trust relationship is explicit. Separate untrusted contributions, routine builds, and release signing with distinct labels, hosts, credentials, and review rules.
What must be removed after a macOS Runner build?
Remove the source checkout, derived data, temporary files, build outputs, generated credentials, keychain imports, and processes started by the job. Do not assume platform cleanup covers host-wide changes. Inspect the filesystem, processes, keychain, environment, caches, and services after a deliberately dirty test.
How can an offline self-hosted Bitbucket Runner recover?
Test the full failure path instead of relying on the online indicator. Stop the runner process, reboot the Mac, interrupt network access, cancel a running task, and confirm unattended return, registration state, log continuity, and new-job acceptance. Record the observed recovery evidence and keep production traffic limited until every required case passes.
A shared Mac or a manually maintained fixed host may appear cheaper at first, but it can introduce procurement delays, fixed capacity, physical replacement work, and difficult remote recovery. A broad Workspace Runner can also create a larger blast radius when repositories share caches, keychains, or host-level state. For temporary projects, staged migration, or a controlled capacity test, renting a remote Mac from CALMVPS can give you a separately managed Mac environment without committing immediately to additional hardware. Review the available Mac plans only after your acceptance criteria are defined.
Start with one non-production pipeline on an isolated Mac node. Pass workspace cleanup, signing separation, routing, and unattended recovery before adding release traffic. If the evidence holds, compare fixed nodes with CALMVPS remote Mac capacity on a project-by-project basis, rather than moving production signing into a shared environment first.