Search code examples
iosjenkinslaunchd

Unable to sign iOS builds with Jenkins


Our Jenkins CI build server is set up on a Mac Mini running OSX Lion (10.7.3), and I'm having trouble getting it to sign the iOS builds so they can be uploaded to to TestFlight.

The process is running as a normal user named jenkins, and it's started at boot time using launchd. (The machine isn't accessible to the outside world, so there shouldn't be any security concerns with running this under a normal user account.)

Here is the error in the console output from jenkins:

[workspace] $ /usr/bin/xcodebuild -target iMobileStCloud -configuration Release clean build
=== CLEAN NATIVE TARGET MyApp OF PROJECT MyProject WITH CONFIGURATION Release ===
Check dependencies
[BEROR]Code Sign error: The identity 'iPhone Distribution' doesn't match any valid certificate/private key pair in the default keychain

Part of the problem seems to be that only the System Keychain is available when the process is started from launchd at boot. I added a script to the build process to list the keychains:

[workspace] $ /bin/sh -xe /var/folders/1y/1q3st_ss58z9ffj4dwbkdw8r0000gt/T/hudson8514187812830984272.sh
+ /usr/bin/security list-keychains
    "/Library/Keychains/System.keychain"
    "/Library/Keychains/applepushserviced.keychain"
    "/Library/Keychains/System.keychain"
+ /usr/bin/security find-identity

I was able to find two workarounds, but neither one is really feasible:

  1. If we login to the server and restart the launchd process every time the machine is rebooted then jenkins is able to load the login keychain and access the certificates for signing:

    sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
    sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist
    
  2. We can add the certificates to the System Keychain, but this means we can't use this machine for doing our app store distribution builds. (Xcode doesn't like the system keychain).

Has anyone else found any other viable workarounds? Is there something else besides launchd that I can use to run processes at boot time on OSX?


Solution

  • I solved this problem by adding SessionCreate=true to my org.jenkins-ci.plist file. This call initializes the Security framework.

    Source: http://developer.apple.com/library/mac/#technotes/tn2083/_index.html

    See mine in its entirety below:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
     <key>EnvironmentVariables</key>
     <dict>
       <key>JENKINS_HOME</key>
       <string>/Users/Shared/Jenkins/Home</string>
     </dict>
    <key>GroupName</key>
    <string>daemon</string>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>org.jenkins-ci</string>
    <key>ProgramArguments</key>
    <array>
      <string>/bin/bash</string>
      <string>/Library/Application Support/Jenkins/jenkins-runner.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>UserName</key>
    <string>jenkins</string>
    <key>SessionCreate</key>
    <true/>
    </dict>
    </plist>