A graphical Terminal signs successfully, but the same Jenkins Job returns errSecInternalComponent.
Run the smallest signing test in graphical Terminal, SSH, and Jenkins with the same macOS account, identity, and test file before importing any certificate again. Then isolate digital identity validity, Keychain access, ACL rules, Agent context, and restart recovery. Production release should use a non-root signing account on an isolated node.
Last updated September 5, 2026. This guide was checked against Apple code-signing guidance, the Apple DTS troubleshooting material revised July 6, 2026, and Jenkins Agent documentation.
[ SECTION_01 ] Who should use this guide
This guide is for platform engineers maintaining Jenkins Mac Agents and restoring iOS or macOS release pipelines.
It also targets security owners responsible for certificate private keys, Keychain permissions, and release audit evidence, plus IT decision-makers evaluating remote Mac nodes for unattended signing.
The core keyword is Jenkins errSecInternalComponent. The issue is not solved reliably by repeated certificate imports because the error can sit at the boundary between a valid identity and the process that is trying to use it.
[ SECTION_02 ] Start with the evidence conflict, not a certificate reinstall
The first useful fact is whether the failure follows the Mac, the user, or Jenkins.
Create one small, non-production signing test. Use the same:
- macOS account
- test file
- signing identity
- Keychain target
codesigncommand- expected verification command
Run it in three contexts:
- A graphical Terminal session.
- An SSH session.
- The Jenkins Job executed by the Agent.
Record the command, exit status, stderr output, user, HOME, and Agent launch method. Do not compare a successful interactive signing command with a Jenkins archive that uses another identity or workspace.
Apple’s code-signing guidance separates certificates, private keys, and digital identities. A certificate shown in a Keychain does not prove that its matching private key is available to the process. The Apple technical note on code-signing certificates should be used as the reference for this distinction.
A useful initial classification looks like this:
- All three contexts fail: inspect the identity, private key, certificate validity, and trust chain.
- Graphical Terminal succeeds, SSH and Jenkins fail: inspect Keychain unlocking and non-interactive access.
- Graphical Terminal and SSH succeed, Jenkins fails: inspect the Agent account,
HOME, launch mode, and process security context. - Only a production identity fails: inspect its private-key ACL, partition rules, expiration, and isolation policy.
- The result changes after reboot: inspect Agent startup and Keychain recovery rather than changing the certificate first.
This classification prevents a local interactive success from being mistaken for production readiness.
[ SECTION_03 ] Digital identity validity is the first metric
The signing identity must be treated as a complete object. It is not enough to find a certificate with the expected team or subject name.
Check these items independently:
- The expected signing certificate exists.
- The corresponding private key exists in the same usable Keychain context.
- The identity appears in the valid signing identity list.
- The certificate is within its validity period.
- The certificate chain is trusted as required by the signing workflow.
- Jenkins is selecting the intended identity rather than a similarly named entry.
A minimal discovery command is:
security find-identity -v -p codesigning
This command is for inventory and evidence. It does not prove that Jenkins can use the private key without interaction.
The distinction matters because several failures can look similar:
- Certificate present, private key absent: the identity is incomplete.
- Certificate and private key present, identity not listed as valid: the chain, trust state, or pairing may be wrong.
- Identity listed, signing fails only in Jenkins: the problem is probably access control or process context.
- Identity works in a graphical session but not over SSH: the identity may be valid while the Keychain session is unavailable.
- Only an expired identity fails: renewal or controlled rotation is required; importing the same material again will not repair it.
Apple’s code-signing documentation is the appropriate source for inspecting how certificates relate to private keys and signing identities. The Apple DTS code-signing discussion also provides the relevant troubleshooting boundary for CI and SSH environments.
Do not paste private keys, certificate contents, or Keychain passwords into Jenkins console output. Store secrets in the approved credential system, restrict job visibility, and redact command output where necessary.
[ SECTION_04 ] macOS Keychain access must be proven without a prompt
The second metric is not whether a Keychain exists. It is whether the Jenkins process can use the intended private key without a graphical prompt.
Graphical login often creates a different security state from SSH. A user may see a working identity in Terminal because the login Keychain is already unlocked. An SSH session can use the same Unix account while lacking the same unlocked Keychain state or search list.
Inspect the effective Keychain state from the same context that will sign:
security list-keychains -d user
security default-keychain -d user
security find-identity -v -p codesigning
The output should be recorded separately for graphical Terminal, SSH, and Jenkins. A matching identity list is useful, but it is still not proof of private-key access.
For an isolated test Keychain, the workflow should be:
- Create or select a non-production test Keychain.
- Import the test certificate and its matching private key through the approved secret-handling process.
- Confirm the identity list.
- Unlock the Keychain only inside the controlled test execution.
- Run
codesignagainst a harmless test file. - Verify the result.
- Lock or remove temporary material after the test.
- Confirm that the workspace contains no exported credential files.
A password placeholder must never be replaced with a real password in a Jenkinsfile, shell history, or ordinary environment variable. The command itself is less important than the control around it: secret injection, process visibility, log masking, cleanup, and auditability.
Private-key access rules also need separate validation. A Keychain may show the certificate and private key while denying the Jenkins process. If an ACL or partition-list adjustment is required, limit access to the signing tools that need it. Avoid granting broad access to every process on the node.
The Apple code-signing reference on certificate structure should be used when documenting the identity and private-key relationship. The team’s evidence should state which Keychain was used, whether it was locked, which process requested the key, and whether a user prompt appeared.
A prompt is a failure signal for unattended production signing. It means the job is depending on a human session or an unrecorded approval step.
[ SECTION_05 ] Jenkins Agent context decides whether the fix reaches the job
The third metric is the effective process context. Jenkins does not automatically inherit the same environment as the engineer’s graphical Terminal.
Capture these values from the Jenkins Job:
id
printf '%s\n' "$HOME"
printf '%s\n' "$PATH"
security default-keychain -d user
security find-identity -v -p codesigning
Compare them with the same commands from the interactive test. The comparison should include:
- Process owner.
- macOS account.
HOME.- Login shell and launch method.
- Keychain search list.
- Default Keychain.
- Available signing identities.
- Whether the process has a graphical login session.
- Whether the Agent was launched manually, by a service, or by another supervisor.
A Unix user change alone does not guarantee a usable Keychain session. Conversely, running a Job as root does not create a safe signing environment. Root can broaden the blast radius, obscure ownership, weaken audit clarity, and expose production private keys to more processes.
The Jenkins Controller credential and the macOS signing identity are different security objects. A Controller credential may authenticate an Agent or fetch a secret. It does not replace the local private key required by codesign. Keep these records separate in the incident report.
Jenkins documents Agent labels and node management as scheduling and execution controls. Use the Jenkins node management documentation to define which jobs can reach a signing node. Use the Jenkins Agent documentation to verify how the Agent starts and under which account.
The decisive test is simple: does the same Job executor that will publish the release also pass the non-interactive signing test? If not, the repair is incomplete.
[ SECTION_06 ] Compare the remediation paths before changing production
The table below scores common paths against the evidence that matters. The score is a decision aid, not a vendor performance claim.
| Remediation path | Identity evidence | Keychain control | Agent context clarity | Release isolation | Restart confidence | Suitable use |
|---|---|---|---|---|---|---|
| Re-import the same certificate | Low | Low | Low | Low | Low | Only when identity material is proven missing or damaged |
| Unlock the existing login Keychain | Medium | Medium | Low | Low | Low | Controlled development or diagnostic testing |
| Dedicated temporary test Keychain | High | High | Medium | Medium | Medium | Reproducing and validating CI signing |
| Dedicated non-root signing account | High | High | High | High | High | Production release node |
| Isolated signing node with restricted labels | High | High | High | High | High | Production publishing and audit-sensitive workflows |
The lowest-confidence path is repeated certificate import. It changes identity material while leaving the process context untouched.
A temporary Keychain is useful for diagnosis because it makes the search scope explicit. It is not automatically the best production design. Production needs a documented ownership model, controlled secret injection, restricted job routing, cleanup verification, and a recovery procedure that does not rely on a person opening a desktop session.
A dedicated signing node is stronger when ordinary pull-request builds do not need access to production private keys. Separate these workloads:
- Pull-request builds: no production signing material.
- Development archives: use non-production identities where possible.
- Release archives: run only on restricted nodes with explicit authorization.
- Publishing tasks: require separate approval and audit evidence.
Use Jenkins labels to keep ordinary jobs away from the release node. The label policy should answer which jobs are allowed, which identities are available, who approved access, and how the node is removed from service after an incident.
[ SECTION_07 ] Isolation limits the damage from a successful build
A successful codesign result does not prove that the node is safe for every Jenkins Job.
The signing node should have a defined trust boundary:
- A dedicated non-root macOS account.
- Only the required signing identities.
- No production private keys on general build nodes.
- Restricted Jenkins labels.
- Separate authorization for release jobs.
- Workspace cleanup after the job.
- Removal of temporary archives, exported profiles, and credential files.
- Log masking for secret-related output.
- Audit records for job, commit, identity, node, and approval.
The security question is not only “can Jenkins sign?” It is also “which other Job can ask the same process to sign?”
If every build can access the production private key, a compromised dependency, malicious pull request, or misconfigured pipeline can turn a build node into a release credential holder. That is an architectural failure even when the current Job is working.
The Jenkins Agent guidance supports separating execution behavior from the Controller’s credential records. The node policy should make the distinction visible: Jenkins schedules work, while the macOS signing context controls access to the local identity.
[ SECTION_08 ] Restart recovery is a release admission metric
A Mac that signs only after an administrator clicks a Keychain dialog is not an unattended production node.
Run the acceptance test under these conditions:
- Fresh graphical login with the designated test account.
- SSH access without opening a graphical desktop.
- Jenkins Agent startup after the Mac reboots.
- A minimal non-production signing test.
- A real archive or equivalent release-stage signing test.
- Workspace and credential cleanup after completion.
The restart test should capture:
- Reboot time and node state.
- Agent startup result.
- Effective process owner and
HOME. - Keychain search list and lock state.
- Identity discovery output.
- Non-interactive
codesignresult. - Archive result.
- Any prompt, timeout, or manual intervention.
- Cleanup verification.
If the Agent reconnects but signing fails, the node is partially recovered. If signing succeeds but the real archive fails, the minimal test was too narrow. If both succeed only after a human unlocks the Keychain, the node fails unattended-release admission.
The acceptance record should contain five linked pieces of evidence: the original failure log, the repair action, the no-prompt signing result, the post-restart retest, and the credential cleanup record. This creates an auditable chain from symptom to release approval.
[ SECTION_09 ] The five-metric diagnosis separates similar symptoms
A compact diagnosis can be written as five scores:
- Identity validity: certificate and private key form a usable identity.
- Keychain accessibility: Jenkins can reach the intended Keychain without a prompt.
- Execution context: the Job runs as the expected account with the expected
HOMEand launch state. - Isolation: only approved Jobs and nodes can reach production signing material.
- Recovery: reboot and Agent reconnect restore signing without human interaction.
A low identity score requires identity repair. A low accessibility score requires Keychain or private-key access work. A low context score requires Agent startup or account correction. A low isolation score requires job routing and credential redesign. A low recovery score blocks production approval even if the current build passes.
This metric model also explains why Jenkins can compile successfully and still fail at codesign: compilation can complete before the pipeline requests a private-key operation. The failure boundary is therefore meaningful evidence, not proof that the entire build environment is broken.
[ SECTION_10 ] Frequently asked questions
The answers below cover the most common enterprise search intents without treating community reports as universal behavior.
Why can Jenkins compile but fail during codesign?
Compilation and signing use different resources. The compiler may need only source files, dependencies, and Xcode tools. codesign also needs a usable digital identity and private-key access. If Jenkins uses another Keychain, account, HOME, or launch context, compilation can pass while signing returns errSecInternalComponent.
What should an SSH session do first?
The SSH session should record its account and HOME, inspect the Keychain search list, list valid signing identities, and run a non-production signing test. It should not immediately re-import certificates. The result must be compared with graphical Terminal and the Jenkins Job using the same file and identity.
Why does Keychain visibility not prove signing access?
The certificate may be visible without its matching private key. The private key may also be locked or restricted by an ACL. Jenkins may be reading a different Keychain from the one shown in the graphical session. Separate evidence is required for certificate presence, private-key presence, identity validity, and actual no-prompt signing.
How should Agent recovery be tested after reboot?
Reboot the Mac, confirm the intended Agent account starts, check its Keychain state, run the minimum signing test, and then run a real archive. Record every prompt and manual action. A node that needs a person to unlock a Keychain after each reboot should remain outside unattended production release.
How can private-key, ACL, and user-context failures be separated?
Run the same test in graphical Terminal, SSH, and Jenkins. Missing identity material suggests a certificate or private-key problem. A visible identity that fails only at signing suggests access control. A result that changes with account, HOME, or Agent launch mode points to user context or Keychain session state.
[ SECTION_11 ] Current hardware versus an isolated remote Mac
Keeping the existing developer Mac or shared office Mac as the signing host can appear simpler, but it creates three operational weaknesses: the machine may be unavailable during release windows, interactive login may be required to restore Keychain access, and production credentials may share a host with unrelated development work.
Buying dedicated hardware solves physical ownership but adds procurement delay, hardware maintenance, replacement planning, remote recovery work, and unused capacity between releases. It also does not automatically solve Jenkins identity or Keychain design.
For a short-term recovery exercise, migration rehearsal, or isolated signing trial, a managed remote Mac can provide graphical access, SSH, a dedicated account, and a separate node without changing the existing production machine first. NOVAKVM’s managed remote Mac access can be evaluated against the same evidence table used here. If the team needs to compare that approach with dedicated Mac hardware planning, the decision should be based on recovery evidence, credential isolation, and expected utilization rather than hardware ownership alone.
The practical boundary is clear: long-running, high-volume workloads may justify owned hardware, while a temporary signing validation node or controlled migration environment can benefit from remote Mac rental. In either case, production approval should wait until the same non-root account, isolated Keychain, Jenkins Agent context, and post-restart signing test all pass without a human prompt.